[Pkg-virtualbox-commits] [kbuild] 01/03: Imported Upstream version 0.1.9998svn2997+dfsg

Gianfranco Costamagna locutusofborg at moszumanska.debian.org
Thu Nov 3 10:35:34 UTC 2016


This is an automated email from the git hooks/post-receive script.

locutusofborg pushed a commit to branch experimental
in repository kbuild.

commit c1266c442ed144fd8b9960294b7e194a5219c7b6
Author: Gianfranco Costamagna <locutusofborg at debian.org>
Date:   Thu Nov 3 11:17:27 2016 +0100

    Imported Upstream version 0.1.9998svn2997+dfsg
---
 kBuild/footer-pass2-compiling-targets.kmk   |    6 +-
 kBuild/footer-pass2-fetches.kmk             |    5 +-
 kBuild/header.kmk                           |   33 +-
 kBuild/tools/NASM.kmk                       |    4 +-
 kBuild/tools/VCC100.kmk                     |  124 +-
 kBuild/tools/VCC100AMD64.kmk                |  166 +-
 kBuild/tools/VCC100X86.kmk                  |  156 +-
 kBuild/units/qt4.kmk                        |   49 +-
 kBuild/units/qt5.kmk                        |   78 +-
 kBuild/units/vccprecomp.kmk                 |   66 +
 src/kDepPre/kDepPre.c                       |    4 +-
 src/kObjCache/kObjCache.c                   |    6 +-
 src/kWorker/Makefile.kmk                    |   13 +-
 src/kWorker/kWorker.c                       | 3789 ++++++++++++++++++++++-----
 src/kmk/Makefile.kmk                        |   20 +-
 src/kmk/dir-nt-bird.c                       |  110 +-
 src/kmk/dir.c                               |    9 +
 src/kmk/function.c                          |   12 +
 src/kmk/kmkbuiltin.c                        |   12 +-
 src/kmk/kmkbuiltin.h                        |   10 +-
 src/kmk/kmkbuiltin/common-env-and-cwd-opt.c |  240 ++
 src/kmk/kmkbuiltin/cp.c                     |    3 +-
 src/kmk/kmkbuiltin/kDepIDB.c                |    4 +-
 src/kmk/kmkbuiltin/kDepObj.c                |   99 +-
 src/kmk/kmkbuiltin/kSubmit.c                |  239 +-
 src/kmk/kmkbuiltin/md5sum.c                 |   42 +-
 src/kmk/kmkbuiltin/redirect.c               | 1817 ++++++++++---
 src/kmk/kmkbuiltin/rm.c                     |   22 +-
 src/kmk/kmkbuiltin/rmdir.c                  |   20 +-
 src/kmk/main.c                              |   39 +-
 src/kmk/make.h                              |    1 +
 src/kmk/w32/include/sub_proc.h              |    1 +
 src/kmk/w32/subproc/sub_proc.c              |   26 +-
 src/lib/Makefile.kmk                        |   11 +-
 src/lib/kDep.c                              |   27 +-
 src/lib/kDep.h                              |    4 +-
 src/lib/kStuff/include/k/kHlpAssert.h       |   20 +-
 src/lib/kStuff/include/k/kTypes.h           |   31 +-
 src/lib/msc_buffered_printf.c               |   18 +-
 src/lib/nt/fts-nt.c                         | 1015 +++++++
 src/lib/nt/fts-nt.h                         |  177 ++
 src/lib/nt/kFsCache.c                       |  826 ++++--
 src/lib/nt/kFsCache.h                       |   98 +-
 src/lib/nt/ntdir.c                          |  125 +-
 src/lib/nt/ntdir.h                          |   18 +-
 src/lib/nt/nthlp.h                          |   23 +-
 src/lib/nt/nthlpcore.c                      |   20 +-
 src/lib/nt/nthlpfs.c                        |  458 +++-
 src/lib/nt/ntstat.c                         |  239 +-
 src/lib/nt/ntstat.h                         |    6 +-
 src/lib/nt/ntstuff.h                        |   58 +-
 src/lib/nt/ntunlink.c                       |   43 +-
 src/lib/nt/ntunlink.h                       |    5 +-
 src/lib/nt/tstNtFts.c                       |  244 ++
 src/lib/quote_argv.c                        |    8 +-
 src/lib/quote_argv.h                        |    4 +-
 56 files changed, 8680 insertions(+), 2023 deletions(-)

diff --git a/kBuild/footer-pass2-compiling-targets.kmk b/kBuild/footer-pass2-compiling-targets.kmk
index a04bdbf..5e3c6a8 100644
--- a/kBuild/footer-pass2-compiling-targets.kmk
+++ b/kBuild/footer-pass2-compiling-targets.kmk
@@ -1,4 +1,4 @@
-# $Id: footer-pass2-compiling-targets.kmk 2795 2015-09-15 23:35:37Z bird $
+# $Id: footer-pass2-compiling-targets.kmk 2952 2016-09-21 18:52:08Z bird $
 ## @file
 # kBuild - Footer - Target lists - Pass 2 - Compiling Targets.
 #
@@ -83,7 +83,7 @@ $(obj) + $($(target)_$(source)_OUTPUT_) +| $($(target)_$(source)_OUTPUT_MAYBE_)
 		$$$$($(target)_INTERMEDIATES.$(bld_trg_cpu)) \
 		$$$$($(target)_INTERMEDIATES.$(bld_type))
 	%$$(call MSG_COMPILE,$(target),$(source),$$@,$(type))
-ifdef TOOL_$(tool)_COMPILE_$(type)_DONT_PURGE_OUTPUT
+ifndef TOOL_$(tool)_COMPILE_$(type)_DONT_PURGE_OUTPUT
 	$$(QUIET)$$(RM) -f -- $(dep) $(obj) $($(target)_$(source)_OUTPUT_) $($(target)_OUTPUT_MAYBE_)
 endif
 endif
@@ -490,6 +490,7 @@ local units       := \
 	$($(target)_USES.$(bld_type))\
 	$($(target)_USES)
 $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre))
+$(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre_2))
 
 # source -> object
 $(evalval def_target_sources)
@@ -694,6 +695,7 @@ local units       := \
 	$($(target)_USES.$(bld_type))\
 	$($(target)_USES)
 $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre))
+$(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre_2))
 
 # source -> object
 $(evalval def_target_sources)
diff --git a/kBuild/footer-pass2-fetches.kmk b/kBuild/footer-pass2-fetches.kmk
index dcd19e8..48f333e 100644
--- a/kBuild/footer-pass2-fetches.kmk
+++ b/kBuild/footer-pass2-fetches.kmk
@@ -1,4 +1,4 @@
-# $Id: footer-pass2-fetches.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: footer-pass2-fetches.kmk 2912 2016-09-14 13:36:15Z bird $
 ## @file
 # kBuild - Footer - Target lists - Pass 2 - Fetches.
 #
@@ -361,6 +361,9 @@ $(out): $(comp-vars _TARGET_$(target)_DIGEST_PREV,_TARGET_$(target)_DIGEST,FORCE
 	%$$(if $$(_TARGET_$(target)_DIGEST),$$(if $$(eq $$(file-size $(out).lst),-1)\
 		,$$(call MSG_REFETCH,$(target)),$$(call MSG_FETCH,$(target))),$$(call MSG_UNFETCH,$(target)))
 	$$(QUIET)$(TEST_EXT) -f $(out).lst -- $$(MAKE) -f $(MAKEFILE) --no-print-directory $(out)_unfetched
+if $(KBUILD_KMK_REVISION) > 2911
+	$$(QUIET)kmk_builtin_dircache deleted "$(dir $(out))"
+endif
 	$$(QUIET)$$(if  $$(_TARGET_$(target)_DIGEST),$$(MAKE) -f $(MAKEFILE) --no-print-directory $(out).lst,$$(RMDIR) -p --ignore-fail-on-non-empty --ignore-fail-on-not-exist -- $$(dir $$@))
 	$$(QUIET2)$$(if $$(_TARGET_$(target)_DIGEST),$$(APPEND) $$@ "_TARGET_$(target)_DIGEST_PREV := $(_TARGET_$(target)_DIGEST)")
 
diff --git a/kBuild/header.kmk b/kBuild/header.kmk
index 462213a..21a0e3d 100644
--- a/kBuild/header.kmk
+++ b/kBuild/header.kmk
@@ -1,4 +1,4 @@
-# $Id: header.kmk 2895 2016-09-08 13:28:37Z bird $
+# $Id: header.kmk 2971 2016-09-27 11:25:09Z bird $
 ## @file
 # kBuild - File included at top of a makefile.
 #
@@ -79,7 +79,7 @@ endif
 # The revision in which this file was last modified.
 # This can be useful when using development versions of kBuild.
 #
-KMK_REVISION := $(patsubst %:,,  $Rev: 2895 $  )
+KMK_REVISION := $(patsubst %:,,  $Rev: 2971 $  )
 
 
 #
@@ -195,6 +195,27 @@ KBUILD_ARCHES_32 := x86 sparc32 s390 ppc32 mips32 hppa32 arm
 
 
 #
+# Mapping of kBuild OS + ARCH to GNU system type wildcards.
+# For use with the foreach/append/prepend and wildcard functions.
+#
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.darwin.x86      = i?86-apple-darwin*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.darwin.amd64    = x86_64-apple-darwin* amd64-apple-darwin*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.freebsd.x86     = i?86-*freebsd*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.freebsd.amd64   = x86_64-*freebsd* amd64-*freebsd*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.linux.x86       = i?86-*linux-gnu
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.linux.amd64     = x86_64-*linux-gnu amd64-*linux-gnu
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.netbsd.x86      = i?86-*netbsd*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.netbsd.amd64    = x86_64-*netbsd* amd64-*netbsd*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.os2.x86         = i?86-*os2*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.x86     = i?86-*solaris2*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.amd64   = amd64-*solaris2* x86_64-*solaris2*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.sparc32 = sparc-*solaris2*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.sparc64 = sparc64-*solaris2* sparcv9-*solaris2*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.win.x86         = i?86-*mingw32* i?86-*msys* i?86-*cygwin*
+KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.win.amd64       = x86_64-*mingw64* amd64-*mingw64* x86_64-*msys* amd64-*msys* x86_64-*cygwin* amd64-*cygwin*
+
+
+#
 # Set default build type.
 #
 ifndef KBUILD_TYPE
@@ -369,6 +390,10 @@ else
  endif
 endif
 
+# Short hand for $(KBUILD_TARGET).$(KBUILD_TARGET_ARCH).
+KBUILD_TARGET_DOT_ARCH = $(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)
+KBUILD_HOST_DOT_ARCH   = $(KBUILD_HOST).$(KBUILD_TARGET_ARCH)
+
 
 #
 # Paths and stuff.
@@ -701,7 +726,11 @@ PRINTF_INT  := kmk_builtin_printf
 PRINTF      := $(PRINTF_INT)
 
 REDIRECT_EXT:= $(KBUILD_BIN_PATH)/kmk_redirect$(HOSTSUFF_EXE)
+if $(KBUILD_KMK_REVISION) > 2911
+REDIRECT_INT:= kmk_builtin_redirect
+else
 REDIRECT_INT:= $(REDIRECT_EXT)
+endif
 REDIRECT    := $(REDIRECT_INT)
 
 RM_EXT      := $(KBUILD_BIN_PATH)/kmk_rm$(HOSTSUFF_EXE)
diff --git a/kBuild/tools/NASM.kmk b/kBuild/tools/NASM.kmk
index 4846033..b3ab243 100644
--- a/kBuild/tools/NASM.kmk
+++ b/kBuild/tools/NASM.kmk
@@ -1,4 +1,4 @@
-# $Id: NASM.kmk 2890 2016-09-07 23:39:29Z bird $
+# $Id: NASM.kmk 2929 2016-09-16 21:19:14Z bird $
 ## @file
 # kBuild Tool Config - Netwide Assembler v0.98+.
 #
@@ -86,7 +86,7 @@ ifdef TOOL_NASM_KSUBMIT
 		-MD "$(dep)" -MP\
 		$(abspath $(source))
 else
-	$(QUIET)$(REDIRECT) -C $(PATH_OUT_BASE) $(TOOL_NASM_AS)\
+	$(QUIET)$(REDIRECT) -C $(PATH_OUT_BASE) -- $(TOOL_NASM_AS)\
 		$(flags) $(addsuffix /,$(addprefix -i, $(incs))) $(addprefix -D, $(defs))\
 		-l $(outbase).lst\
 		-o $(obj)\
diff --git a/kBuild/tools/VCC100.kmk b/kBuild/tools/VCC100.kmk
index e47e887..34ed55a 100644
--- a/kBuild/tools/VCC100.kmk
+++ b/kBuild/tools/VCC100.kmk
@@ -1,4 +1,4 @@
-# $Id: VCC100.kmk 2795 2015-09-15 23:35:37Z bird $
+# $Id: VCC100.kmk 2964 2016-09-23 11:08:04Z bird $
 ## @file
 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting $(KBUILD_TARGET).
 #
@@ -107,19 +107,21 @@ TOOL_VCC100_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC100_FN_FIND_SDK_
 # @param    $(2)        The extension.
 TOOL_VCC100_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2)
 
+
+# General Properties used by kBuild
 TOOL_VCC100_COBJSUFF         ?= .obj
-TOOL_VCC100_CFLAGS           ?= -TC -nologo
-TOOL_VCC100_CFLAGS.debug     ?= -Zi
-TOOL_VCC100_CFLAGS.dbgopt    ?= -O2 -Zi
+TOOL_VCC100_CFLAGS           ?= -TC -nologo -Zi
+TOOL_VCC100_CFLAGS.debug     ?=
+TOOL_VCC100_CFLAGS.dbgopt    ?= -O2
 TOOL_VCC100_CFLAGS.release   ?= -O2
 TOOL_VCC100_CFLAGS.profile   ?= -O2
 TOOL_VCC100_CINCS            ?= $(PATH_TOOL_VCC100_INC)
 TOOL_VCC100_CDEFS            ?=
 
 TOOL_VCC100_CXXOBJSUFF       ?= .obj
-TOOL_VCC100_CXXFLAGS         ?= -TP -nologo
-TOOL_VCC100_CXXFLAGS.debug   ?= -Zi
-TOOL_VCC100_CXXFLAGS.dbgopt  ?= -O2 -Zi
+TOOL_VCC100_CXXFLAGS         ?= -TP -nologo -Zi
+TOOL_VCC100_CXXFLAGS.debug   ?=
+TOOL_VCC100_CXXFLAGS.dbgopt  ?= -O2
 TOOL_VCC100_CXXFLAGS.release ?= -O2
 TOOL_VCC100_CXXFLAGS.profile ?= -O2
 TOOL_VCC100_CXXINCS          ?= $(PATH_TOOL_VCC100_INC) $(PATH_TOOL_VCC100_ATLMFC_INC)
@@ -162,37 +164,16 @@ TOOL_VCC100_LIBPATH.x86      ?= $(PATH_TOOL_VCC100_LIB.x86) $(PATH_TOOL_VCC100_A
 # @param    $(objsuff)  Object suffix.
 TOOL_VCC100_COMPILE_C_DEPEND =
 TOOL_VCC100_COMPILE_C_DEPORD =
-ifdef KBUILD_USE_KOBJCACHE
-TOOL_VCC100_COMPILE_C_USES_KOBJCACHE = 1
-TOOL_VCC100_COMPILE_C_OUTPUT = $(outbase).i
-TOOL_VCC100_COMPILE_C_OUTPUT_MAYBE =
-define TOOL_VCC100_COMPILE_C_CMDS
-	$(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
-		--make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
-		--kObjCache-cpp $(outbase).i\
-		$(TOOL_VCC100_CC) -E\
-		$(subst -Zi,-Z7,$(flags))\
-		$(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		$(subst /,\\,$(abspath $(source))) \
-		--kObjCache-cc $(obj)\
-		$(TOOL_VCC100_CC) -c\
-		$(subst -Zi,-Z7,$(flags))\
-		-Fo$(obj)\
-		$(outbase).i
-endef
-else  # !KBUILD_USE_KOBJCACHE
-TOOL_VCC100_COMPILE_C_OUTPUT = $(call TOOL_VCC100_PDB, $(outbase)-obj,idb)
-TOOL_VCC100_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100_PDB, $(outbase)-obj,pdb)
+TOOL_VCC100_COMPILE_C_OUTPUT =
+TOOL_VCC100_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100_PDB, $(outbase)-obj,idb)
 define TOOL_VCC100_COMPILE_C_CMDS
 	$(QUIET)$(TOOL_VCC100_CC) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
 		-Fd$(outbase)-obj.pdb \
-		-FD\
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-	$(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100_PDB,$(outbase)-obj,idb)
+	$(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
 endef
-endif # !KBUILD_USE_KOBJCACHE
 
 
 ## Compile C++ source.
@@ -208,39 +189,66 @@ endif # !KBUILD_USE_KOBJCACHE
 #
 # @param    $(outbase)  Output basename (full). Use this for list files and such.
 # @param    $(objsuff)  Object suffix.
-TOOL_VCC100_COMPILE_CXX_DEPEND =
+TOOL_VCC100_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE)
 TOOL_VCC100_COMPILE_CXX_DEPORD =
-ifdef KBUILD_USE_KOBJCACHE
-TOOL_VCC100_COMPILE_CXX_USES_KOBJCACHE = 1
-TOOL_VCC100_COMPILE_CXX_OUTPUT = $(outbase).ii
-TOOL_VCC100_COMPILE_CXX_OUTPUT_MAYBE =
-define TOOL_VCC100_COMPILE_CXX_CMDS
-	$(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
-		--make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
-		--kObjCache-cpp $(outbase).ii\
-		$(TOOL_VCC100_CXX) -E\
-		$(subst -Zi,-Z7,$(flags))\
-		$(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		$(subst /,\\,$(abspath $(source))) \
-		--kObjCache-cc $(obj)\
-		$(TOOL_VCC100_CXX) -c\
-		$(subst -Zi,-Z7,$(flags))\
-		-Fo$(obj)\
-		$(outbase).ii
-endef
-else  # !KBUILD_USE_KOBJCACHE
-TOOL_VCC100_COMPILE_CXX_OUTPUT = $(call TOOL_VCC100_PDB, $(outbase)-obj,idb)
-TOOL_VCC100_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC100_PDB, $(outbase)-obj,pdb)
+TOOL_VCC100_COMPILE_CXX_OUTPUT =
+TOOL_VCC100_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\
+	,,$(call TOOL_VCC100_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100_PDB, $(outbase)-obj,idb))
 define TOOL_VCC100_COMPILE_CXX_CMDS
 	$(QUIET)$(TOOL_VCC100_CXX) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		-Fd$(outbase)-obj.pdb \
-		-FD\
+		$(if-expr defined($(target)_PCH_HDR)\
+		,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
+		-Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-	$(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100_PDB,$(outbase)-obj,idb)
+	$(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
 endef
-endif # !KBUILD_USE_KOBJCACHE
+
+
+#
+# Helper tool for creating the precompiled C++ header.
+#
+# It only have the C++ compile bits and it's purpose is to skip bits
+# related _1_VCC_PCH_FILE and add -Yc.
+#
+TOOL_VCC100-PCH                         := Helper for creating precompiled header using CXX handling.
+TOOL_VCC100-PCH_EXTENDS                 := VCC100
+TOOL_VCC100-PCH_CXXOBJSUFF              := .obj
+TOOL_VCC100-PCH_CXXINCS                  = $(TOOL_VCC100_CXXINCS)
+TOOL_VCC100-PCH_CXXFLAGS.debug           = $(TOOL_VCC100_CXXFLAGS.debug)
+TOOL_VCC100-PCH_CXXFLAGS.dbgopt          = $(TOOL_VCC100_CXXFLAGS.dbgopt)
+TOOL_VCC100-PCH_CXXFLAGS.release         = $(TOOL_VCC100_CXXFLAGS.release)
+TOOL_VCC100-PCH_CXXFLAGS.profile         = $(TOOL_VCC100_CXXFLAGS.profile)
+TOOL_VCC100-PCH_COMPILE_CXX_DEPEND       = $(NO_SUCH_VARIABLE)
+TOOL_VCC100-PCH_COMPILE_CXX_DEPORD       = $(NO_SUCH_VARIABLE)
+TOOL_VCC100-PCH_COMPILE_CXX_OUTPUT       = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
+TOOL_VCC100-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE)
+ifdef TOOL_VCC100_KSUBMIT
+ define TOOL_VCC100-PCH_COMPILE_CXX_CMDS
+	$(QUIET)$(TOOL_VCC100_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
+		-- $(TOOL_VCC100_CXX) -c -Yc\
+		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
+               -Fp$($(target)_1_VCC_PCH_FILE) \
+		-Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
+		-Fo$(obj)\
+               -TP \
+		$(subst /,\\,$(abspath $(source)))
+ endef
+else
+ define TOOL_VCC100-PCH_COMPILE_CXX_CMDS
+	$(QUIET)$(TOOL_VCC100_CXX) -c -Yc\
+		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
+               -Fp$($(target)_1_VCC_PCH_FILE) \
+		-Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
+		-Fo$(obj)\
+               -TP \
+		$(subst /,\\,$(abspath $(source)))
+	$(QUIET)$(DEP_OBJ) -f -s -q  -e .pch -o $(dep) -t $(obj) $(obj)
+
+ endef
+endif # !TOOL_VCC100_KSUBMIT
+
 
 ## @todo configure the assembler template.
 
@@ -293,8 +301,6 @@ define TOOL_VCC100_LINK_LIBRARY_CMDS
 endef
 
 
-
-
 ## Link program
 # @param    $(target)       Normalized main target name.
 # @param    $(out)          Program name.
diff --git a/kBuild/tools/VCC100AMD64.kmk b/kBuild/tools/VCC100AMD64.kmk
index a4740db..316882f 100644
--- a/kBuild/tools/VCC100AMD64.kmk
+++ b/kBuild/tools/VCC100AMD64.kmk
@@ -1,4 +1,4 @@
-# $Id: VCC100AMD64.kmk 2902 2016-09-09 17:15:22Z bird $
+# $Id: VCC100AMD64.kmk 2964 2016-09-23 11:08:04Z bird $
 ## @file
 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting AMD64.
 #
@@ -79,10 +79,12 @@ ifdef TOOL_VCC100AMD64_USE_KSUBMIT
  ifeq ($(KBUILD_HOST),win)
   ifneq ($(substr $(PATH_TOOL_VCC100AMD64_BIN),-9),x86_amd64)
    TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --64-bit
+   TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
   else
-   TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --32-bit
+   # "fatal error C1902: Program database manager mismatch; please check your installation" when mixing with the 32-bit compiler.
+   #TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --32-bit
+   #TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
   endif
-  TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
  endif
 endif
 
@@ -103,19 +105,21 @@ TOOL_VCC100_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC100_FN_FIND_SDK_
 # @param    $(2)        The extension.
 TOOL_VCC100AMD64_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2)
 
+
+# General Properties used by kBuild
 TOOL_VCC100AMD64_COBJSUFF         ?= .obj
-TOOL_VCC100AMD64_CFLAGS           ?= -TC -nologo
-TOOL_VCC100AMD64_CFLAGS.debug     ?= -Zi
-TOOL_VCC100AMD64_CFLAGS.dbgopt    ?= -O2 -Zi
+TOOL_VCC100AMD64_CFLAGS           ?= -TC -nologo -Zi
+TOOL_VCC100AMD64_CFLAGS.debug     ?=
+TOOL_VCC100AMD64_CFLAGS.dbgopt    ?= -O2
 TOOL_VCC100AMD64_CFLAGS.release   ?= -O2
 TOOL_VCC100AMD64_CFLAGS.profile   ?= -O2
 TOOL_VCC100AMD64_CINCS            ?= $(PATH_TOOL_VCC100AMD64_INC)
 TOOL_VCC100AMD64_CDEFS            ?=
 
 TOOL_VCC100AMD64_CXXOBJSUFF       ?= .obj
-TOOL_VCC100AMD64_CXXFLAGS         ?= -TP -nologo
-TOOL_VCC100AMD64_CXXFLAGS.debug   ?= -Zi
-TOOL_VCC100AMD64_CXXFLAGS.dbgopt  ?= -O2 -Zi
+TOOL_VCC100AMD64_CXXFLAGS         ?= -TP -nologo -Zi
+TOOL_VCC100AMD64_CXXFLAGS.debug   ?=
+TOOL_VCC100AMD64_CXXFLAGS.dbgopt  ?= -O2
 TOOL_VCC100AMD64_CXXFLAGS.release ?= -O2
 TOOL_VCC100AMD64_CXXFLAGS.profile ?= -O2
 TOOL_VCC100AMD64_CXXINCS          ?= $(PATH_TOOL_VCC100AMD64_INC) $(PATH_TOOL_VCC100AMD64_ATLMFC_INC)
@@ -152,49 +156,28 @@ TOOL_VCC100AMD64_LDFLAGS.release  ?=
 # @param    $(objsuff)  Object suffix.
 TOOL_VCC100AMD64_COMPILE_C_DEPEND =
 TOOL_VCC100AMD64_COMPILE_C_DEPORD =
-ifdef KBUILD_USE_KOBJCACHE
-TOOL_VCC100AMD64_COMPILE_C_USES_KOBJCACHE = 1
-TOOL_VCC100AMD64_COMPILE_C_OUTPUT = $(outbase).i
-TOOL_VCC100AMD64_COMPILE_C_OUTPUT_MAYBE =
-define TOOL_VCC100AMD64_COMPILE_C_CMDS
-	$(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
-		--make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
-		--kObjCache-cpp $(outbase).i\
-		$(TOOL_VCC100AMD64_CC) -E\
-		$(subst -Zi,-Z7,$(flags))\
-		$(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		$(subst /,\\,$(abspath $(source))) \
-		--kObjCache-cc $(obj)\
-		$(TOOL_VCC100AMD64_CC) -c\
-		$(subst -Zi,-Z7,$(flags))\
-		-Fo$(obj)\
-		$(outbase).i
-endef
-else  # !KBUILD_USE_KOBJCACHE
-TOOL_VCC100AMD64_COMPILE_C_OUTPUT = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb)
-TOOL_VCC100AMD64_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb)
- ifdef TOOL_VCC100AMD64_KSUBMIT
-define TOOL_VCC100AMD64_COMPILE_C_CMDS
+TOOL_VCC100AMD64_COMPILE_C_OUTPUT =
+TOOL_VCC100AMD64_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb)
+ifdef TOOL_VCC100AMD64_KSUBMIT
+ TOOL_VCC100AMD64_COMPILE_C_DONT_PURGE_OUTPUT := 1 # speed
+ define TOOL_VCC100AMD64_COMPILE_C_CMDS
 	$(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
 		-- $(TOOL_VCC100AMD64_CC) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
 		-Fd$(outbase)-obj.pdb \
-		-FD\
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-endef
- else
-define TOOL_VCC100AMD64_COMPILE_C_CMDS
+ endef
+else
+ define TOOL_VCC100AMD64_COMPILE_C_CMDS
 	$(QUIET)$(TOOL_VCC100AMD64_CC) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
 		-Fd$(outbase)-obj.pdb \
-		-FD\
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-	$(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100AMD64_PDB,$(outbase)-obj,idb)
-endef
- endif # !TOOL_VCC100AMD64_KSUBMIT
-endif # !KBUILD_USE_KOBJCACHE
+	$(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
+ endef
+endif # !TOOL_VCC100AMD64_KSUBMIT
 
 
 ## Compile C++ source.
@@ -210,51 +193,82 @@ endif # !KBUILD_USE_KOBJCACHE
 #
 # @param    $(outbase)  Output basename (full). Use this for list files and such.
 # @param    $(objsuff)  Object suffix.
-TOOL_VCC100AMD64_COMPILE_CXX_DEPEND =
+TOOL_VCC100AMD64_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE)
 TOOL_VCC100AMD64_COMPILE_CXX_DEPORD =
-ifdef KBUILD_USE_KOBJCACHE
-TOOL_VCC100AMD64_COMPILE_CXX_USES_KOBJCACHE = 1
-TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT = $(outbase).ii
-TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT_MAYBE =
-define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
-	$(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
-		--make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
-		--kObjCache-cpp $(outbase).ii\
-		$(TOOL_VCC100AMD64_CXX) -E\
-		$(subst -Zi,-Z7,$(flags))\
-		$(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		$(subst /,\\,$(abspath $(source))) \
-		--kObjCache-cc $(obj)\
-		$(TOOL_VCC100AMD64_CXX) -c\
-		$(subst -Zi,-Z7,$(flags))\
-		-Fo$(obj)\
-		$(outbase).ii
-endef
-else  # !KBUILD_USE_KOBJCACHE
-TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb)
-TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb)
- ifdef TOOL_VCC100AMD64_KSUBMIT
-define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
+TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT =
+TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\
+	,,$(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb))
+ifdef TOOL_VCC100AMD64_KSUBMIT
+ TOOL_VCC100AMD64_COMPILE_CXX_DONT_PURGE_OUTPUT := 1 # speed
+ define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
 	$(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
 		-- $(TOOL_VCC100AMD64_CXX) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		-Fd$(outbase)-obj.pdb \
-		-FD\
+		$(if-expr defined($(target)_PCH_HDR)\
+		,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
+		-Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-endef
- else
-define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
+ endef
+else
+ define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
 	$(QUIET)$(TOOL_VCC100AMD64_CXX) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		-Fd$(outbase)-obj.pdb \
-		-FD\
+		$(if-expr defined($(target)_PCH_HDR)\
+		,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
+		-Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-	$(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100AMD64_PDB,$(outbase)-obj,idb)
-endef
- endif # !TOOL_VCC100AMD64_KSUBMIT
-endif # !KBUILD_USE_KOBJCACHE
+	$(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
+ endef
+endif # !TOOL_VCC100AMD64_KSUBMIT
+
+
+#
+# Helper tool for creating the precompiled C++ header.
+#
+# It only have the C++ compile bits and it's purpose is to skip bits
+# related _1_VCC_PCH_FILE and add -Yc.
+#
+TOOL_VCC100AMD64-PCH                         := Helper for creating precompiled header using CXX handling.
+TOOL_VCC100AMD64-PCH_EXTENDS                 := VCC100AMD64
+TOOL_VCC100AMD64-PCH_CXXOBJSUFF              := .obj
+TOOL_VCC100AMD64-PCH_CXXINCS                  = $(TOOL_VCC100AMD64_CXXINCS)
+TOOL_VCC100AMD64-PCH_CXXFLAGS.debug           = $(TOOL_VCC100AMD64_CXXFLAGS.debug)
+TOOL_VCC100AMD64-PCH_CXXFLAGS.dbgopt          = $(TOOL_VCC100AMD64_CXXFLAGS.dbgopt)
+TOOL_VCC100AMD64-PCH_CXXFLAGS.release         = $(TOOL_VCC100AMD64_CXXFLAGS.release)
+TOOL_VCC100AMD64-PCH_CXXFLAGS.profile         = $(TOOL_VCC100AMD64_CXXFLAGS.profile)
+TOOL_VCC100AMD64-PCH_COMPILE_CXX_DEPEND       = $(NO_SUCH_VARIABLE)
+TOOL_VCC100AMD64-PCH_COMPILE_CXX_DEPORD       = $(NO_SUCH_VARIABLE)
+TOOL_VCC100AMD64-PCH_COMPILE_CXX_OUTPUT       = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
+TOOL_VCC100AMD64-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE)
+ifdef TOOL_VCC100AMD64_KSUBMIT
+ define TOOL_VCC100AMD64-PCH_COMPILE_CXX_CMDS
+	$(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
+	$(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
+		-- $(TOOL_VCC100AMD64_CXX) -c -Yc\
+		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
+               -Fp$($(target)_1_VCC_PCH_FILE) \
+		-Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
+		-Fo$(obj)\
+               -TP \
+		$(subst /,\\,$(abspath $(source)))
+ endef
+else
+ define TOOL_VCC100AMD64-PCH_COMPILE_CXX_CMDS
+	$(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
+	$(QUIET)$(TOOL_VCC100AMD64_CXX) -c -Yc\
+		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
+               -Fp$($(target)_1_VCC_PCH_FILE) \
+		-Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
+		-Fo$(obj)\
+               -TP \
+		$(subst /,\\,$(abspath $(source)))
+	$(QUIET)$(DEP_OBJ) -f -s -q  -e .pch -o $(dep) -t $(obj) $(obj)
+
+ endef
+endif # !TOOL_VCC100AMD64_KSUBMIT
+
 
 ## @todo configure the assembler template.
 
diff --git a/kBuild/tools/VCC100X86.kmk b/kBuild/tools/VCC100X86.kmk
index 95d6ac8..fb81816 100644
--- a/kBuild/tools/VCC100X86.kmk
+++ b/kBuild/tools/VCC100X86.kmk
@@ -1,4 +1,4 @@
-# $Id: VCC100X86.kmk 2902 2016-09-09 17:15:22Z bird $
+# $Id: VCC100X86.kmk 2964 2016-09-23 11:08:04Z bird $
 ## @file
 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting x86.
 #
@@ -101,18 +101,18 @@ TOOL_VCC100X86_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2)
 
 # General Properties used by kBuild
 TOOL_VCC100X86_COBJSUFF         ?= .obj
-TOOL_VCC100X86_CFLAGS           ?= -TC -nologo
-TOOL_VCC100X86_CFLAGS.debug     ?= -Zi
-TOOL_VCC100X86_CFLAGS.dbgopt    ?= -O2 -Zi
+TOOL_VCC100X86_CFLAGS           ?= -TC -nologo -Zi
+TOOL_VCC100X86_CFLAGS.debug     ?=
+TOOL_VCC100X86_CFLAGS.dbgopt    ?= -O2
 TOOL_VCC100X86_CFLAGS.release   ?= -O2
 TOOL_VCC100X86_CFLAGS.profile   ?= -O2
 TOOL_VCC100X86_CINCS            ?= $(PATH_TOOL_VCC100X86_INC)
 TOOL_VCC100X86_CDEFS            ?=
 
 TOOL_VCC100X86_CXXOBJSUFF       ?= .obj
-TOOL_VCC100X86_CXXFLAGS         ?= -TP -nologo
-TOOL_VCC100X86_CXXFLAGS.debug   ?= -Zi
-TOOL_VCC100X86_CXXFLAGS.dbgopt  ?= -O2 -Zi
+TOOL_VCC100X86_CXXFLAGS         ?= -TP -nologo -Zi
+TOOL_VCC100X86_CXXFLAGS.debug   ?=
+TOOL_VCC100X86_CXXFLAGS.dbgopt  ?= -O2
 TOOL_VCC100X86_CXXFLAGS.release ?= -O2
 TOOL_VCC100X86_CXXFLAGS.profile ?= -O2
 TOOL_VCC100X86_CXXINCS          ?= $(PATH_TOOL_VCC100X86_INC) $(PATH_TOOL_VCC100X86_ATLMFC_INC)
@@ -149,49 +149,28 @@ TOOL_VCC100X86_LDFLAGS.release  ?=
 # @param    $(objsuff)  Object suffix.
 TOOL_VCC100X86_COMPILE_C_DEPEND =
 TOOL_VCC100X86_COMPILE_C_DEPORD =
-ifdef KBUILD_USE_KOBJCACHE
-TOOL_VCC100X86_COMPILE_C_USES_KOBJCACHE = 1
-TOOL_VCC100X86_COMPILE_C_OUTPUT = $(outbase).i
-TOOL_VCC100X86_COMPILE_C_OUTPUT_MAYBE =
-define TOOL_VCC100X86_COMPILE_C_CMDS
-	$(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
-		--make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
-		--kObjCache-cpp $(outbase).i\
-		$(TOOL_VCC100X86_CC) -E\
-		$(subst -Zi,-Z7,$(flags))\
-		$(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		$(subst /,\\,$(abspath $(source))) \
-		--kObjCache-cc $(obj)\
-		$(TOOL_VCC100X86_CC) -c\
-		$(subst -Zi,-Z7,$(flags))\
-		-Fo$(obj)\
-		$(outbase).i
-endef
-else  # !KBUILD_USE_KOBJCACHE
-TOOL_VCC100X86_COMPILE_C_OUTPUT = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb)
-TOOL_VCC100X86_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb)
- ifdef TOOL_VCC100X86_KSUBMIT
-define TOOL_VCC100X86_COMPILE_C_CMDS
+TOOL_VCC100X86_COMPILE_C_OUTPUT =
+TOOL_VCC100X86_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb)
+ifdef TOOL_VCC100X86_KSUBMIT
+ TOOL_VCC100X86_COMPILE_C_DONT_PURGE_OUTPUT = 1 # speed
+ define TOOL_VCC100X86_COMPILE_C_CMDS
 	$(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
 		-- $(TOOL_VCC100X86_CC) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
 		-Fd$(outbase)-obj.pdb \
-		-FD\
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-endef
- else
-define TOOL_VCC100X86_COMPILE_C_CMDS
+ endef
+else
+ define TOOL_VCC100X86_COMPILE_C_CMDS
 	$(QUIET)$(TOOL_VCC100X86_CC) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
 		-Fd$(outbase)-obj.pdb \
-		-FD\
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-	$(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100X86_PDB,$(outbase)-obj,idb)
-endef
- endif # !TOOL_VCC100X86_KSUBMIT
-endif # !KBUILD_USE_KOBJCACHE
+	$(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
+ endef
+endif # !TOOL_VCC100X86_KSUBMIT
 
 
 ## Compile C++ source.
@@ -207,51 +186,80 @@ endif # !KBUILD_USE_KOBJCACHE
 #
 # @param    $(outbase)  Output basename (full). Use this for list files and such.
 # @param    $(objsuff)  Object suffix.
-TOOL_VCC100X86_COMPILE_CXX_DEPEND =
+TOOL_VCC100X86_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE)
 TOOL_VCC100X86_COMPILE_CXX_DEPORD =
-ifdef KBUILD_USE_KOBJCACHE
-TOOL_VCC100X86_COMPILE_CXX_USES_KOBJCACHE = 1
-TOOL_VCC100X86_COMPILE_CXX_OUTPUT = $(outbase).ii
-TOOL_VCC100X86_COMPILE_CXX_OUTPUT_MAYBE =
-define TOOL_VCC100X86_COMPILE_CXX_CMDS
-	$(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
-		--make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
-		--kObjCache-cpp $(outbase).ii\
-		$(TOOL_VCC100X86_CXX) -E\
-		$(subst -Zi,-Z7,$(flags))\
-		$(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		$(subst /,\\,$(abspath $(source))) \
-		--kObjCache-cc $(obj)\
-		$(TOOL_VCC100X86_CXX) -c\
-		$(subst -Zi,-Z7,$(flags))\
-		-Fo$(obj)\
-		$(outbase).ii
-endef
-else  # !KBUILD_USE_KOBJCACHE
-TOOL_VCC100X86_COMPILE_CXX_OUTPUT = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb)
-TOOL_VCC100X86_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb)
- ifdef TOOL_VCC100X86_KSUBMIT
-define TOOL_VCC100X86_COMPILE_CXX_CMDS
+TOOL_VCC100X86_COMPILE_CXX_OUTPUT =
+TOOL_VCC100X86_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\
+	,,$(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb))
+ifdef TOOL_VCC100X86_KSUBMIT
+ TOOL_VCC100X86_COMPILE_CXX_DONT_PURGE_OUTPUT = 1 # speed
+ define TOOL_VCC100X86_COMPILE_CXX_CMDS
 	$(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
 		-- $(TOOL_VCC100X86_CXX) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		-Fd$(outbase)-obj.pdb \
-		-FD\
+		$(if-expr defined($(target)_PCH_HDR)\
+		,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
+		-Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-endef
- else
-define TOOL_VCC100X86_COMPILE_CXX_CMDS
+ endef
+else
+ define TOOL_VCC100X86_COMPILE_CXX_CMDS
 	$(QUIET)$(TOOL_VCC100X86_CXX) -c\
 		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
-		-Fd$(outbase)-obj.pdb \
-		-FD\
+		$(if-expr defined($(target)_PCH_HDR)\
+		,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
+		-Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
 		-Fo$(obj)\
 		$(subst /,\\,$(abspath $(source)))
-	$(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100X86_PDB,$(outbase)-obj,idb)
-endef
- endif # !TOOL_VCC100X86_KSUBMIT
-endif # !KBUILD_USE_KOBJCACHE
+	$(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
+ endef
+endif # !TOOL_VCC100X86_KSUBMIT
+
+
+#
+# Helper tool for creating the precompiled C++ header.
+#
+# It only have the C++ compile bits and it's purpose is to skip bits
+# related _1_VCC_PCH_FILE and add -Yc.
+#
+TOOL_VCC100X86-PCH                         := Helper for creating precompiled header using CXX handling.
+TOOL_VCC100X86-PCH_EXTENDS                 := VCC100X86
+TOOL_VCC100X86-PCH_CXXOBJSUFF              := .obj
+TOOL_VCC100X86-PCH_CXXINCS                  = $(TOOL_VCC100X86_CXXINCS)
+TOOL_VCC100X86-PCH_CXXFLAGS.debug           = $(TOOL_VCC100X86_CXXFLAGS.debug)
+TOOL_VCC100X86-PCH_CXXFLAGS.dbgopt          = $(TOOL_VCC100X86_CXXFLAGS.dbgopt)
+TOOL_VCC100X86-PCH_CXXFLAGS.release         = $(TOOL_VCC100X86_CXXFLAGS.release)
+TOOL_VCC100X86-PCH_CXXFLAGS.profile         = $(TOOL_VCC100X86_CXXFLAGS.profile)
+TOOL_VCC100X86-PCH_COMPILE_CXX_DEPEND       = $(NO_SUCH_VARIABLE)
+TOOL_VCC100X86-PCH_COMPILE_CXX_DEPORD       = $(NO_SUCH_VARIABLE)
+TOOL_VCC100X86-PCH_COMPILE_CXX_OUTPUT       = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
+TOOL_VCC100X86-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE)
+ifdef TOOL_VCC100X86_KSUBMIT
+ define TOOL_VCC100X86-PCH_COMPILE_CXX_CMDS
+	$(QUIET)$(TOOL_VCC100X86_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
+		-- $(TOOL_VCC100X86_CXX) -c -Yc\
+		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
+               -Fp$($(target)_1_VCC_PCH_FILE) \
+		-Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
+		-Fo$(obj)\
+               -TP \
+		$(subst /,\\,$(abspath $(source)))
+ endef
+else
+ define TOOL_VCC100X86-PCH_COMPILE_CXX_CMDS
+	$(QUIET)$(TOOL_VCC100X86_CXX) -c -Yc\
+		$(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
+               -Fp$($(target)_1_VCC_PCH_FILE) \
+		-Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
+		-Fo$(obj)\
+               -TP \
+		$(subst /,\\,$(abspath $(source)))
+	$(QUIET)$(DEP_OBJ) -f -s -q  -e .pch -o $(dep) -t $(obj) $(obj)
+
+ endef
+endif # !TOOL_VCC100X86_KSUBMIT
+
 
 ## @todo configure the assembler template.
 
diff --git a/kBuild/units/qt4.kmk b/kBuild/units/qt4.kmk
index dde5991..553fb89 100644
--- a/kBuild/units/qt4.kmk
+++ b/kBuild/units/qt4.kmk
@@ -1,4 +1,4 @@
-# $Id: qt4.kmk 2805 2016-01-28 11:08:44Z bird $
+# $Id: qt4.kmk 2979 2016-09-27 14:36:32Z bird $
 ## @file
 # Qt 4 unit.
 #
@@ -103,6 +103,7 @@ ifndef PATH_SDK_QT4
     endif
     ifeq ($(PATH_SDK_QT4),)
      PATH_SDK_QT4 := $(patsubst %/bin/rcc,%,$(firstword $(wildcard \
+       /usr/lib/*/qt4/bin/rcc \
      	/usr/bin/rcc \
      	/usr/local/bin/rcc \
      	/usr/qt/4/bin/rcc \
@@ -115,6 +116,7 @@ ifndef PATH_SDK_QT4
      # Locate the include files.
      ifeq ($(PATH_SDK_QT4_INC),)
       PATH_SDK_QT4_INC := $(patsubst %/QtCore/qglobal.h,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/include/$(type)/qt4/QtCore/qglobal.h) \
 	$(PATH_SDK_QT4)/include/QtCore/qglobal.h \
 	$(PATH_SDK_QT4)/include/qt4/QtCore/qglobal.h \
 	/usr/include/qt4/QtCore/qtglobal.h \
@@ -132,10 +134,10 @@ ifndef PATH_SDK_QT4
 	$(PATH_SDK_QT4)/lib32/qt4/libQtCore$(SUFF_DLL) \
 	/usr/lib32/libQtCore$(SUFF_DLL) \
 	/usr/lib32/qt4/libQtCore$(SUFF_DLL) \
-	/usr/lib/i386-linux-gnu/libQtCore$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \
 	/usr/local/lib32/libQtCore$(SUFF_DLL) \
 	/usr/local/lib32/qt4/libQtCore$(SUFF_DLL) \
-	/usr/local/lib/i386-linux-gnu/libQtCore$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \
 	$(PATH_SDK_QT4)/lib/libQtCore$(SUFF_DLL) \
 	$(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \
 	$(PATH_SDK_QT4)/lib/i386-linux-gnu/libQtCore$(SUFF_DLL) \
@@ -152,11 +154,11 @@ ifndef PATH_SDK_QT4
 	/usr/lib64/libQtCore$(SUFF_DLL) \
 	/usr/lib64/qt4/libQtCore$(SUFF_DLL) \
 	/usr/lib/amd64/libQtCore$(SUFF_DLL) \
-	/usr/lib/x86_64-linux-gnu/libQtCore$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \
 	/usr/local/lib64/libQtCore$(SUFF_DLL) \
 	/usr/local/lib64/qt4/libQtCore$(SUFF_DLL) \
 	/usr/local/lib/amd64/libQtCore$(SUFF_DLL) \
-	/usr/local/lib/x86_64-linux-gnu/libQtCore$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \
 	$(PATH_SDK_QT4)/lib/libQtCore$(SUFF_DLL) \
 	$(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \
 	$(PATH_SDK_QT4)/lib/x86_64-linux-gnu/libQtCore$(SUFF_DLL) \
@@ -175,8 +177,10 @@ ifndef PATH_SDK_QT4
        	$(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \
        	/usr/lib/libQtCore$(SUFF_DLL) \
        	/usr/lib/qt4/libQtCore$(SUFF_DLL) \
+       	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \
        	/usr/local/lib/libQtCore$(SUFF_DLL) \
        	/usr/local/lib/qt4/libQtCore$(SUFF_DLL) \
+       	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \
        	)))
       endif
       ifneq ($(PATH_SDK_QT4_LIB),)
@@ -241,9 +245,10 @@ ifndef PATH_TOOL_QT4_BIN
   ifdef TOOL_QT4_BIN_SUFF
    TOOL_QT4_BIN_SUFF := $(TOOL_QT4_BIN_SUFF)
   endif
-  # Try looking for moc-qt4 / moc-$(suffix) first.
+  # Try looking for moc-$(suffix) first, if specified.
   ifneq ($(TOOL_QT4_BIN_SUFF),)
    PATH_TOOL_QT4_BIN := $(patsubst %/moc$(TOOL_QT4_BIN_SUFF),%,$(firstword $(wildcard \
+	 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc$(TOOL_QT4_BIN_SUFF)) \
 	 /usr/lib/qt4/bin/moc$(TOOL_QT4_BIN_SUFF) \
 	 /usr/qt/4/bin/moc$(TOOL_QT4_BIN_SUFF) \
 	 /usr/share/qt4/bin/moc$(TOOL_QT4_BIN_SUFF) \
@@ -251,27 +256,35 @@ ifndef PATH_TOOL_QT4_BIN
 	 /usr/bin/moc$(TOOL_QT4_BIN_SUFF) \
 	 )))
   else
-   PATH_TOOL_QT4_BIN := $(patsubst %/moc-qt4,%,$(firstword $(wildcard \
+   # No suffix given, so before we check out -qt4 look at qt4 specific locations to avoid choosers and symlinks.
+   PATH_TOOL_QT4_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc) \
+	$(if $(intersects $(KBUILD_HOST_ARCH), $(KBUILD_ARCHES_64)),/usr/lib64/qt4/bin/moc,) \
+	/usr/lib/qt4/bin/moc \
+	/usr/local/lib/qt4/bin/moc \
+	/usr/qt/4/bin/moc \
+	/usr/local/qt/4/bin/moc \
+	/usr/share/qt4/bin/moc \
+	/usr/local/share/qt4/bin/moc \
+	)))
+   ifeq ($(PATH_TOOL_QT4_BIN),)
+    PATH_TOOL_QT4_BIN := $(patsubst %/moc-qt4,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc-qt4) \
 	/usr/lib/qt4/bin/moc-qt4 \
 	/usr/qt/4/bin/moc-qt4 \
 	/usr/share/qt4/bin/moc-qt4 \
 	/usr/local/bin/moc-qt4 \
 	/usr/bin/moc-qt4 \
 	)))
-   ifneq ($(PATH_TOOL_QT4_BIN),)
-    TOOL_QT4_BIN_SUFF := -qt4
-   else
-    # If no luck, try looking for moc in the qt4 specific locations.
-    PATH_TOOL_QT4_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
-	/usr/lib/qt4/bin/moc \
-	/usr/qt/4/bin/moc \
-	/usr/share/qt4/bin/moc \
-	)))
+    ifneq ($(PATH_TOOL_QT4_BIN),)
+     TOOL_QT4_BIN_SUFF := -qt4
+    endif
    endif
   endif
   # If still no go, try looking for qt3to4 and rcc.
   ifeq ($(PATH_TOOL_QT4_BIN),)
    PATH_TOOL_QT4_BIN := $(patsubst %/qt3to4,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/qt3to4) \
 	/usr/lib/qt4/bin/qt3to4 \
 	/usr/qt/4/bin/qt3to4 \
 	/usr/share/qt4/bin/qt3to4 \
@@ -281,6 +294,7 @@ ifndef PATH_TOOL_QT4_BIN
   endif
   ifeq ($(PATH_TOOL_QT4_BIN),)
    PATH_TOOL_QT4_BIN := $(patsubst %/rcc$(TOOL_QT4_BIN_SUFF),%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF)) \
 	/usr/lib/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF) \
 	/usr/qt/4/bin/rcc$(TOOL_QT4_BIN_SUFF) \
 	/usr/share/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF) \
@@ -290,6 +304,7 @@ ifndef PATH_TOOL_QT4_BIN
   endif
   if "$(PATH_TOOL_QT4_BIN)" == "" && "$(TOOL_QT4_BIN_SUFF)" != ""
    PATH_TOOL_QT4_BIN := $(patsubst %/rcc,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/rcc) \
 	/usr/lib/qt4/bin/rcc \
 	/usr/qt/4/bin/rcc \
 	/usr/share/qt4/bin/rcc \
@@ -321,7 +336,7 @@ else
  # Pathless, relies on the environment.
  TOOL_QT4_MOC       ?= moc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
  TOOL_QT4_UIC       ?= uic$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
- TOOL_QT4_RCC       ?= rcc$(HOST_SUFF_EXE)
+ TOOL_QT4_RCC       ?= rcc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
  TOOL_QT4_LRC       ?= lrelease$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
  TOOL_QT4_LUPDATE   ?= lupdate$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
 endif
diff --git a/kBuild/units/qt5.kmk b/kBuild/units/qt5.kmk
index 5334910..67e5baf 100644
--- a/kBuild/units/qt5.kmk
+++ b/kBuild/units/qt5.kmk
@@ -1,4 +1,4 @@
-# $Id: qt5.kmk 2807 2016-01-28 13:21:41Z bird $
+# $Id: qt5.kmk 2980 2016-09-27 14:40:53Z bird $
 ## @file
 # Qt 5 unit.
 #
@@ -103,6 +103,7 @@ ifndef PATH_SDK_QT5
     endif
     ifeq ($(PATH_SDK_QT5),)
      PATH_SDK_QT5 := $(patsubst %/bin/rcc,%,$(firstword $(wildcard \
+       /usr/lib/*/qt5/bin/rcc \
      	/usr/bin/rcc \
      	/usr/local/bin/rcc \
      	/usr/qt/5/bin/rcc \
@@ -115,10 +116,11 @@ ifndef PATH_SDK_QT5
      # Locate the include files.
      ifeq ($(PATH_SDK_QT5_INC),)
       PATH_SDK_QT5_INC := $(patsubst %/QtCore/qglobal.h,%,$(firstword $(wildcard \
-	$(PATH_SDK_QT5)/include/QtCore/qglobal.h \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/include/$(type)/qt5/QtCore/qglobal.h) \
 	$(PATH_SDK_QT5)/include/qt5/QtCore/qglobal.h \
 	/usr/include/qt5/QtCore/qtglobal.h \
 	/usr/local/include/qt5/QtCore/qtglobal.h \
+	$(PATH_SDK_QT5)/include/QtCore/qglobal.h \
 	)))
       ifneq ($(PATH_SDK_QT5_INC),)
        export PATH_SDK_QT5_INC
@@ -132,10 +134,10 @@ ifndef PATH_SDK_QT5
 	$(PATH_SDK_QT5)/lib32/qt5/libQt5Core$(SUFF_DLL) \
 	/usr/lib32/libQt5Core$(SUFF_DLL) \
 	/usr/lib32/qt5/libQt5Core$(SUFF_DLL) \
-	/usr/lib/i386-linux-gnu/libQt5Core$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \
 	/usr/local/lib32/libQt5Core$(SUFF_DLL) \
 	/usr/local/lib32/qt5/libQt5Core$(SUFF_DLL) \
-	/usr/local/lib/i386-linux-gnu/libQt5Core$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \
 	$(PATH_SDK_QT5)/lib/libQt5Core$(SUFF_DLL) \
 	$(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \
 	$(PATH_SDK_QT5)/lib/i386-linux-gnu/libQt5Core$(SUFF_DLL) \
@@ -152,11 +154,11 @@ ifndef PATH_SDK_QT5
 	/usr/lib64/libQt5Core$(SUFF_DLL) \
 	/usr/lib64/qt5/libQt5Core$(SUFF_DLL) \
 	/usr/lib/amd64/libQt5Core$(SUFF_DLL) \
-	/usr/lib/x86_64-linux-gnu/libQt5Core$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \
 	/usr/local/lib64/libQt5Core$(SUFF_DLL) \
 	/usr/local/lib64/qt5/libQt5Core$(SUFF_DLL) \
 	/usr/local/lib/amd64/libQt5Core$(SUFF_DLL) \
-	/usr/local/lib/x86_64-linux-gnu/libQt5Core$(SUFF_DLL) \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \
 	$(PATH_SDK_QT5)/lib/libQt5Core$(SUFF_DLL) \
 	$(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \
 	$(PATH_SDK_QT5)/lib/x86_64-linux-gnu/libQt5Core$(SUFF_DLL) \
@@ -175,8 +177,10 @@ ifndef PATH_SDK_QT5
        	$(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \
        	/usr/lib/libQt5Core$(SUFF_DLL) \
        	/usr/lib/qt5/libQt5Core$(SUFF_DLL) \
+       	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \
        	/usr/local/lib/libQt5Core$(SUFF_DLL) \
        	/usr/local/lib/qt5/libQt5Core$(SUFF_DLL) \
+       	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \
        	)))
       endif
       ifneq ($(PATH_SDK_QT5_LIB),)
@@ -244,6 +248,7 @@ ifndef PATH_TOOL_QT5_BIN
   # Try looking for moc-qt5 / moc-$(suffix) first.
   ifneq ($(TOOL_QT5_BIN_SUFF),)
    PATH_TOOL_QT5_BIN := $(patsubst %/moc$(TOOL_QT5_BIN_SUFF),%,$(firstword $(wildcard \
+	 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc$(TOOL_QT5_BIN_SUFF)) \
 	 /usr/lib/qt5/bin/moc$(TOOL_QT5_BIN_SUFF) \
 	 /usr/qt/5/bin/moc$(TOOL_QT5_BIN_SUFF) \
 	 /usr/share/qt5/bin/moc$(TOOL_QT5_BIN_SUFF) \
@@ -251,27 +256,35 @@ ifndef PATH_TOOL_QT5_BIN
 	 /usr/bin/moc$(TOOL_QT5_BIN_SUFF) \
 	 )))
   else
-   PATH_TOOL_QT5_BIN := $(patsubst %/moc-qt5,%,$(firstword $(wildcard \
+   # No suffix given, so before we check out -qt5 look at qt5 specific locations to avoid choosers and symlinks.
+   PATH_TOOL_QT5_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc) \
+	$(if $(intersects $(KBUILD_HOST_ARCH), $(KBUILD_ARCHES_64)),/usr/lib64/qt5/bin/moc,) \
+	/usr/lib/qt5/bin/moc \
+	/usr/local/lib/qt5/bin/moc \
+	/usr/qt/5/bin/moc \
+	/usr/local/qt/5/bin/moc \
+	/usr/share/qt5/bin/moc \
+	/usr/local/share/qt5/bin/moc \
+	)))
+   ifeq ($(PATH_TOOL_QT5_BIN),)
+    PATH_TOOL_QT5_BIN := $(patsubst %/moc-qt5,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc-qt5) \
 	/usr/lib/qt5/bin/moc-qt5 \
 	/usr/qt/5/bin/moc-qt5 \
 	/usr/share/qt5/bin/moc-qt5 \
 	/usr/local/bin/moc-qt5 \
 	/usr/bin/moc-qt5 \
 	)))
-   ifneq ($(PATH_TOOL_QT5_BIN),)
-    TOOL_QT5_BIN_SUFF := -qt5
-   else
-    # If no luck, try looking for moc in the qt5 specific locations.
-    PATH_TOOL_QT5_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
-	/usr/lib/qt5/bin/moc \
-	/usr/qt/5/bin/moc \
-	/usr/share/qt5/bin/moc \
-	)))
+    ifneq ($(PATH_TOOL_QT5_BIN),)
+     TOOL_QT5_BIN_SUFF := -qt5
+    endif
    endif
   endif
   # If still no go, try looking for qt4to5 and rcc.
   ifeq ($(PATH_TOOL_QT5_BIN),)
    PATH_TOOL_QT5_BIN := $(patsubst %/qt4to5,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/qt4to5) \
 	/usr/lib/qt5/bin/qt4to5 \
 	/usr/qt/5/bin/qt4to5 \
 	/usr/share/qt5/bin/qt4to5 \
@@ -281,6 +294,7 @@ ifndef PATH_TOOL_QT5_BIN
   endif
   ifeq ($(PATH_TOOL_QT5_BIN),)
    PATH_TOOL_QT5_BIN := $(patsubst %/rcc$(TOOL_QT5_BIN_SUFF),%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF)) \
 	/usr/lib/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF) \
 	/usr/qt/5/bin/rcc$(TOOL_QT5_BIN_SUFF) \
 	/usr/share/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF) \
@@ -290,6 +304,7 @@ ifndef PATH_TOOL_QT5_BIN
   endif
   if "$(PATH_TOOL_QT5_BIN)" == "" && "$(TOOL_QT5_BIN_SUFF)" != ""
    PATH_TOOL_QT5_BIN := $(patsubst %/rcc,%,$(firstword $(wildcard \
+	$(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/rcc) \
 	/usr/lib/qt5/bin/rcc \
 	/usr/qt/5/bin/rcc \
 	/usr/share/qt5/bin/rcc \
@@ -307,23 +322,28 @@ else
  PATH_TOOL_QT5_BIN := $(PATH_TOOL_QT5_BIN)
 endif
 ifneq ($(PATH_TOOL_QT5_BIN),)
- TOOL_QT5_MOC       ?= $(PATH_TOOL_QT5_BIN)/moc$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
- TOOL_QT5_UIC       ?= $(PATH_TOOL_QT5_BIN)/uic$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
+ TOOL_QT5_MOC       ?= $(PATH_TOOL_QT5_BIN)/moc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
+ TOOL_QT5_UIC       ?= $(PATH_TOOL_QT5_BIN)/uic$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
  ifndef TOOL_QT5_RCC
-  TOOL_QT5_RCC      := $(PATH_TOOL_QT5_BIN)/rcc$(HOST_SUFF_EXE)
+  TOOL_QT5_RCC      := $(PATH_TOOL_QT5_BIN)/rcc$(HOSTSUFF_EXE)
   ifeq ($(wildcard $(TOOL_QT5_RCC)),)
-   TOOL_QT5_RCC     := $(PATH_TOOL_QT5_BIN)/rcc$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
+   TOOL_QT5_RCC     := $(PATH_TOOL_QT5_BIN)/rcc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
   endif
  endif
- TOOL_QT5_LRC       ?= $(PATH_TOOL_QT5_BIN)/lrelease$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
- TOOL_QT5_LUPDATE   ?= $(PATH_TOOL_QT5_BIN)/lupdate$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
+ TOOL_QT5_LRC       ?= $(PATH_TOOL_QT5_BIN)/lrelease$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
+ TOOL_QT5_LUPDATE   ?= $(PATH_TOOL_QT5_BIN)/lupdate$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
 else
  # Pathless, relies on the environment.
- TOOL_QT5_MOC       ?= moc$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
- TOOL_QT5_UIC       ?= uic$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
- TOOL_QT5_RCC       ?= rcc$(HOST_SUFF_EXE)
- TOOL_QT5_LRC       ?= lrelease$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
- TOOL_QT5_LUPDATE   ?= lupdate$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
+ TOOL_QT5_MOC       ?= moc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
+ TOOL_QT5_UIC       ?= uic$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
+ TOOL_QT5_RCC       ?= rcc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
+ TOOL_QT5_LRC       ?= lrelease$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
+ TOOL_QT5_LUPDATE   ?= lupdate$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
+endif
+ifdef TOOL_QT5_USE_KSUBMIT
+ ifeq ($(KBUILD_HOST),win)
+  TOOL_QT5_MOC_KSUBMIT ?= kmk_builtin_kSubmit --$(SP)
+ endif
 endif
 
 # General Properties used by kBuild and/or units/qt.kmk
@@ -351,7 +371,7 @@ TOOL_QT5_MOC_CPP_DEPORD =
 TOOL_QT5_MOC_CPP_OUTPUT =
 TOOL_QT5_MOC_CPP_OUTPUT_MAYBE =
 define TOOL_QT5_MOC_CPP_CMDS
-	$(QUIET)$(TOOL_QT5_MOC)\
+	$(QUIET)$(TOOL_QT5_MOC_KSUBMIT)$(TOOL_QT5_MOC)\
 		$(flags)\
 		$(addprefix -I, $(incs))\
 		$(addprefix -D, $(defs))\
@@ -374,7 +394,7 @@ TOOL_QT5_MOC_HPP_DEPORD =
 TOOL_QT5_MOC_HPP_OUTPUT =
 TOOL_QT5_MOC_HPP_OUTPUT_MAYBE =
 define TOOL_QT5_MOC_HPP_CMDS
-	$(QUIET)$(TOOL_QT5_MOC)\
+	$(QUIET)$(TOOL_QT5_MOC_KSUBMIT)$(TOOL_QT5_MOC)\
 		$(flags)\
 		$(addprefix -I, $(incs))\
 		$(addprefix -D, $(defs))\
diff --git a/kBuild/units/vccprecomp.kmk b/kBuild/units/vccprecomp.kmk
new file mode 100644
index 0000000..290dcad
--- /dev/null
+++ b/kBuild/units/vccprecomp.kmk
@@ -0,0 +1,66 @@
+# $Id: vccprecomp.kmk 2956 2016-09-21 19:37:20Z bird $
+## @file
+# kBuild Unit - Target Level Precompiled Headers for Visual C++.
+#
+
+#
+# Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spam-xiv at anduin.net>
+#
+# This file is part of kBuild.
+#
+# kBuild is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# kBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with kBuild; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#
+# As a special exception you are granted permission to include this file, via
+# the kmk include directive, as you wish without this in itself causing the
+# resulting makefile, program or whatever to be covered by the GPL license.
+# This exception does not however invalidate any other reasons why the makefile,
+# program, whatever should not be covered the GPL.
+#
+#
+
+
+UNIT_vccprecomp = Target level precompiled Headers for Visual C++
+
+#
+# Early target processing pass #1.
+#
+# This set the internal _VCC_PCH_FILE and VCC_COMMON_OBJ_PDB properties,
+# which will be picked up by the VCCxxx tool.
+#
+define def_unit_vccprecomp_target_pre
+ $(target)_1_VCC_PCH_FILE       := $(outbase)-pch.pch
+ $(target)_1_VCC_COMMON_OBJ_PDB := $(outbase)-common-obj.pdb
+endef
+
+#
+# Early target processing pass #2.
+#
+# This sets up a rule for creating the .pch file after qt5 and similar units
+# are done modifying INCS, DEFS and company.  The 'tool' variable is defined by
+# footer-pass2-compiling-targets.kmk and is really the LD tool, but that'll
+# have to do for now.  The '-PCH' variant of the VCC tool, is defined together
+# with $(tool) and allow us to bypass the options and dependencies triggered
+# by _1_VCC_PCH_FILE, _1_VCC_COMMON_OBJ_PDB and _PCH_HDR, and also make sure we
+# don't get circular dependencies by way of kDepObj and the debug info.
+#
+define def_unit_vccprecomp_target_pre_2
+ local source := $($(target)_PCH_HDR)
+ $(source)_TOOL := $(tool)-PCH
+ local suff   := $(suffix $(source))
+ local type   := CXX
+ $(kb-src-one 2)
+endef
+
diff --git a/src/kDepPre/kDepPre.c b/src/kDepPre/kDepPre.c
index 0b40e51..e677b5b 100644
--- a/src/kDepPre/kDepPre.c
+++ b/src/kDepPre/kDepPre.c
@@ -1,4 +1,4 @@
-/* $Id: kDepPre.c 2413 2010-09-11 17:43:04Z bird $ */
+/* $Id: kDepPre.c 2955 2016-09-21 19:05:53Z bird $ */
 /** @file
  * kDepPre - Dependency Generator using Precompiler output.
  */
@@ -464,7 +464,7 @@ int main(int argc, char *argv[])
      */
     if (!i)
     {
-        depOptimize(fFixCase, 0 /* fQuiet */);
+        depOptimize(fFixCase, 0 /* fQuiet */, NULL /*pszIgnoredExt*/);
         fprintf(pOutput, "%s:", pszTarget);
         depPrint(pOutput);
         if (fStubs)
diff --git a/src/kObjCache/kObjCache.c b/src/kObjCache/kObjCache.c
index d6badb7..fdb0697 100644
--- a/src/kObjCache/kObjCache.c
+++ b/src/kObjCache/kObjCache.c
@@ -1,4 +1,4 @@
-/* $Id: kObjCache.c 2627 2012-08-09 14:12:12Z bird $ */
+/* $Id: kObjCache.c 2955 2016-09-21 19:05:53Z bird $ */
 /** @file
  * kObjCache - Object Cache.
  */
@@ -1100,7 +1100,7 @@ static void kOCDepWriteToFile(PKOCDEP pDepState, const char *pszFilename, const
     if (!pFile)
         FatalMsg("Failed to open dependency file '%s': %s\n", pszFilename, strerror(errno));
 
-    depOptimize(fFixCase, fQuiet);
+    depOptimize(fFixCase, fQuiet, NULL /*pszIgnoredExt*/);
 
     /* Make object file name with unix slashes. */
     pszObjFileAbs = MakePathFromDirAndFile(pszObjFile, pszObjDir);
@@ -5087,7 +5087,7 @@ int main(int argc, char **argv)
         }
         else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version"))
         {
-            printf("kObjCache - kBuild version %d.%d.%d ($Revision: 2627 $)\n"
+            printf("kObjCache - kBuild version %d.%d.%d ($Revision: 2955 $)\n"
                    "Copyright (c) 2007-2012 knut st. osmundsen\n",
                    KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
             return 0;
diff --git a/src/kWorker/Makefile.kmk b/src/kWorker/Makefile.kmk
index 2016bb8..2f0331b 100644
--- a/src/kWorker/Makefile.kmk
+++ b/src/kWorker/Makefile.kmk
@@ -1,4 +1,4 @@
-# $Id: Makefile.kmk 2894 2016-09-08 13:27:56Z bird $
+# $Id: Makefile.kmk 2968 2016-09-26 18:14:50Z bird $
 ## @file
 # Sub-makefile for kWorker.
 #
@@ -30,6 +30,7 @@ include $(PATH_KBUILD)/subheader.kmk
 
 PROGRAMS += kWorker
 kWorker_TEMPLATE = BIN-STATIC-THREADED
+kWorker_DEFS := KWORKER
 kWorker_DEFS.debug = K_STRICT
 kWorker_DEFS.release = NASSERT
 kWorker_SOURCES = \
@@ -47,7 +48,9 @@ kWorker_LIBS.win = \
 	$(PATH_SDK_WINDDK71_LIB_WNET)/ntdll.lib \
 	$(PATH_SDK_WINDDK71_LIB_WNET)/psapi.lib
 kWorker_LDFLAGS.win = \
-	/BASE:0x10000 /DYNAMICBASE:NO /FIXED /SECTION:DefLdBuf,EWR
+	/BASE:0x10000 /DYNAMICBASE:NO /FIXED
+#kWorker_LDFLAGS.win.x86 = \
+#	/SAFESEH:NO - doesn't help anyone.
 
 
 #
@@ -57,6 +60,7 @@ LIBRARIES += kWorkerLib
 kWorkerLib_TEMPLATE = LIB-STATIC-THREADED
 kWorkerLib_DEFPATH = ../lib # Need fix from r2837.
 kWorkerLib_DEFPATH := $(PATH_SUB_CURRENT)/../lib
+kWorkerLib_DEFS := KWORKER
 kWorkerLib_SOURCES = \
 	crc32.c \
 	md5.c \
@@ -72,7 +76,10 @@ kWorkerLib_SOURCES.win = \
        nt/ntstat.c \
        nt/ntunlink.c \
        nt/kFsCache.c \
-       quote_argv.c
+       quote_argv.c \
+	maybe_con_write.c \
+	maybe_con_fwrite.c \
+	msc_buffered_printf.c
 kbuild_version.c_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV)
 
 #
diff --git a/src/kWorker/kWorker.c b/src/kWorker/kWorker.c
index 6962738..13e7d94 100644
--- a/src/kWorker/kWorker.c
+++ b/src/kWorker/kWorker.c
@@ -1,4 +1,4 @@
-/* $Id: kWorker.c 2906 2016-09-09 22:15:57Z bird $ */
+/* $Id: kWorker.c 2987 2016-11-01 18:27:39Z bird $ */
 /** @file
  * kWorker - experimental process reuse worker for Windows.
  *
@@ -31,6 +31,9 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
 //#undef NDEBUG
+//#define K_STRICT 1
+//#define KW_LOG_ENABLED
+
 #define PSAPI_VERSION 1
 #include <k/kHlp.h>
 #include <k/kLdr.h>
@@ -40,16 +43,16 @@
 #include <setjmp.h>
 #include <ctype.h>
 #include <errno.h>
+#include <process.h>
 
 #include "nt/ntstat.h"
 #include "kbuild_version.h"
-/* lib/nt_fullpath.c */
-extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
 
 #include "nt/ntstuff.h"
 #include <psapi.h>
 
 #include "nt/kFsCache.h"
+#include "nt_fullpath.h"
 #include "quote_argv.h"
 #include "md5.h"
 
@@ -69,37 +72,91 @@ extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
  * they are included. */
 #define WITH_HASH_MD5_CACHE
 
+/** @def WITH_CRYPT_CTX_REUSE
+ * Enables reusing crypt contexts.  The Visual C++ compiler always creates a
+ * context which is only used for MD5 and maybe some random bytes (VS 2010).
+ * So, only create it once and add a reference to it instead of creating new
+ * ones.  Saves registry access among other things. */
+#define WITH_CRYPT_CTX_REUSE
+
 /** @def WITH_CONSOLE_OUTPUT_BUFFERING
  * Enables buffering of all console output as well as removal of annoying
  * source file echo by cl.exe. */
 #define WITH_CONSOLE_OUTPUT_BUFFERING
 
+/** @def WITH_STD_OUT_ERR_BUFFERING
+ * Enables buffering of standard output and standard error buffer as well as
+ * removal of annoying source file echo by cl.exe. */
+#define WITH_STD_OUT_ERR_BUFFERING
 
-/** String constant comma length.   */
-#define TUPLE(a_sz)                     a_sz, sizeof(a_sz) - 1
+/** @def WITH_LOG_FILE
+ * Log to file instead of stderr. */
+#define WITH_LOG_FILE
+
+/** @def WITH_HISTORY
+ * Keep history of the last jobs.  For debugging.  */
+#define WITH_HISTORY
+
+/** @def WITH_FIXED_VIRTUAL_ALLOCS
+ * Whether to pre allocate memory for known fixed VirtualAlloc calls (currently
+ * there is only one, but an important one, from cl.exe).
+ */
+#if K_ARCH == K_ARCH_X86_32
+# define WITH_FIXED_VIRTUAL_ALLOCS
+#endif
+
+/** @def WITH_PCH_CACHING
+ * Enables read caching of precompiled header files. */
+#if K_ARCH_BITS >= 64
+# define WITH_PCH_CACHING
+#endif
+
+
+#ifndef NDEBUG
+# define KW_LOG_ENABLED
+#endif
 
 /** @def KW_LOG
  * Generic logging.
  * @param a     Argument list for kwDbgPrintf  */
-#ifndef NDEBUG
+#ifdef KW_LOG_ENABLED
 # define KW_LOG(a) kwDbgPrintf a
 #else
 # define KW_LOG(a) do { } while (0)
 #endif
 
+/** @def KWLDR_LOG
+ * Loader related logging.
+ * @param a     Argument list for kwDbgPrintf  */
+#ifdef KW_LOG_ENABLED
+# define KWLDR_LOG(a) kwDbgPrintf a
+#else
+# define KWLDR_LOG(a) do { } while (0)
+#endif
+
+
 /** @def KWFS_LOG
  * FS cache logging.
  * @param a     Argument list for kwDbgPrintf  */
-#ifndef NDEBUG
+#ifdef KW_LOG_ENABLED
 # define KWFS_LOG(a) kwDbgPrintf a
 #else
 # define KWFS_LOG(a) do { } while (0)
 #endif
 
+/** @def KWOUT_LOG
+ * Output related logging.
+ * @param a     Argument list for kwDbgPrintf  */
+#ifdef KW_LOG_ENABLED
+# define KWOUT_LOG(a) kwDbgPrintf a
+#else
+# define KWOUT_LOG(a) do { } while (0)
+#endif
+
 /** @def KWCRYPT_LOG
  * FS cache logging.
  * @param a     Argument list for kwDbgPrintf  */
-#ifndef NDEBUG
+#ifdef KW_LOG_ENABLED
 # define KWCRYPT_LOG(a) kwDbgPrintf a
 #else
 # define KWCRYPT_LOG(a) do { } while (0)
@@ -122,9 +179,9 @@ extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
 
 /** Marks unfinished code.  */
 #if 1
-# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); __debugbreak(); } while (0)
+# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); __debugbreak(); } while (0)
 #else
-# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); } while (0)
+# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); } while (0)
 #endif
 
 /** User data key for tools. */
@@ -132,6 +189,9 @@ extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
 /** User data key for a cached file. */
 #define KW_DATA_KEY_CACHED_FILE         (~(KUPTR)65521)
 
+/** String constant comma length.   */
+#define TUPLE(a_sz)                     a_sz, sizeof(a_sz) - 1
+
 
 /*********************************************************************************************************************************
 *   Structures and Typedefs                                                                                                      *
@@ -188,9 +248,9 @@ typedef struct KWMODULE
         struct
         {
             /** Where we load the image. */
-            void               *pvLoad;
+            KU8                *pbLoad;
             /** Virgin copy of the image. */
-            void               *pvCopy;
+            KU8                *pbCopy;
             /** Ldr pvBits argument.  This is NULL till we've successfully resolved
              *  the imports. */
             void               *pvBits;
@@ -206,6 +266,32 @@ typedef struct KWMODULE
 #endif
             /** Set if we share memory with other executables. */
             KBOOL               fUseLdBuf;
+            /** Set after the first whole image copy is done. */
+            KBOOL               fCanDoQuick;
+            /** Number of quick copy chunks. */
+            KU8                 cQuickCopyChunks;
+            /** Number of quick zero chunks. */
+            KU8                 cQuickZeroChunks;
+            /** Quicker image copy instructions that skips non-writable parts when
+             * possible.  Need to check fCanDoQuick, fUseLdBuf and previous executable
+             * image. */
+            struct
+            {
+                /** The copy destination.   */
+                KU8            *pbDst;
+                /** The copy source.   */
+                KU8 const      *pbSrc;
+                /** How much to copy. */
+                KSIZE           cbToCopy;
+            } aQuickCopyChunks[3];
+            /** For handling BSS and zero alignment padding when using aQuickCopyChunks. */
+            struct
+            {
+                /** Where to start zeroing. */
+                KU8            *pbDst;
+                /** How much to zero. */
+                KSIZE           cbToZero;
+            } aQuickZeroChunks[3];
             /** Number of imported modules. */
             KSIZE               cImpMods;
             /** Import array (variable size). */
@@ -260,6 +346,8 @@ typedef struct KFSWCACHEDFILE
 
     /** Cached file handle. */
     HANDLE              hCached;
+    /** Cached file section handle. */
+    HANDLE              hSection;
     /** Cached file content. */
     KU8                *pbCached;
     /** The file size. */
@@ -353,25 +441,49 @@ typedef struct KWFSTEMPFILE
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
 
 /**
- * Console line buffer.
+ * Console line buffer or output full buffer.
  */
-typedef struct KWCONSOLEOUTPUTLINE
+typedef struct KWOUTPUTSTREAMBUF
 {
     /** The main output handle. */
     HANDLE              hOutput;
     /** Our backup handle. */
     HANDLE              hBackup;
-    /** Set if this is a console handle. */
+    /** Set if this is a console handle and we're in line buffered mode.
+     * When clear, we may buffer multiple lines, though try flush on line
+     * boundraries when ever possible. */
     KBOOL               fIsConsole;
-    /** Amount of pending console output in wchar_t's. */
-    KU32                cwcBuf;
-    /** The allocated buffer size.   */
-    KU32                cwcBufAlloc;
-    /** Pending console output. */
-    wchar_t            *pwcBuf;
-} KWCONSOLEOUTPUTLINE;
+    /** Compressed GetFileType result. */
+    KU8                 fFileType;
+    KU8                 abPadding[2];
+    union
+    {
+        /** Line buffer mode (fIsConsole == K_TRUE). */
+        struct
+        {
+            /** Amount of pending console output in wchar_t's. */
+            KU32                cwcBuf;
+            /** The allocated buffer size.   */
+            KU32                cwcBufAlloc;
+            /** Pending console output. */
+            wchar_t            *pwcBuf;
+        } Con;
+        /** Fully buffered mode (fIsConsole == K_FALSE). */
+        struct
+        {
+            /** Amount of pending output (in chars). */
+            KU32                cchBuf;
+#ifdef WITH_STD_OUT_ERR_BUFFERING
+            /** The allocated buffer size (in chars).   */
+            KU32                cchBufAlloc;
+            /** Pending output. */
+            char               *pchBuf;
+#endif
+        } Fully;
+    } u;
+} KWOUTPUTSTREAMBUF;
 /** Pointer to a console line buffer. */
-typedef KWCONSOLEOUTPUTLINE *PKWCONSOLEOUTPUTLINE;
+typedef KWOUTPUTSTREAMBUF *PKWOUTPUTSTREAMBUF;
 
 /**
  * Combined console buffer of complete lines.
@@ -401,15 +513,18 @@ typedef enum KWHANDLETYPE
 {
     KWHANDLETYPE_INVALID = 0,
     KWHANDLETYPE_FSOBJ_READ_CACHE,
+    KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING,
     KWHANDLETYPE_TEMP_FILE,
-    KWHANDLETYPE_TEMP_FILE_MAPPING
-    //KWHANDLETYPE_CONSOLE_CACHE
+    KWHANDLETYPE_TEMP_FILE_MAPPING,
+    KWHANDLETYPE_OUTPUT_BUF
 } KWHANDLETYPE;
 
 /** Handle data. */
 typedef struct KWHANDLE
 {
     KWHANDLETYPE        enmType;
+    /** Number of references   */
+    KU32                cRefs;
     /** The current file offset. */
     KU32                offFile;
     /** Handle access. */
@@ -424,10 +539,38 @@ typedef struct KWHANDLE
         PKFSWCACHEDFILE     pCachedFile;
         /** Temporary file handle or mapping handle. */
         PKWFSTEMPFILE       pTempFile;
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+        /** Buffered output stream. */
+        PKWOUTPUTSTREAMBUF  pOutBuf;
+#endif
     } u;
 } KWHANDLE;
 typedef KWHANDLE *PKWHANDLE;
 
+/**
+ * Tracking one of our memory mappings.
+ */
+typedef struct KWMEMMAPPING
+{
+    /** Number of references. */
+    KU32                cRefs;
+    /** The mapping type (KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING or
+     *  KWHANDLETYPE_TEMP_FILE_MAPPING). */
+    KWHANDLETYPE        enmType;
+    /** The mapping address. */
+    PVOID               pvMapping;
+    /** Type specific data. */
+    union
+    {
+        /** The file system object.   */
+        PKFSWCACHEDFILE     pCachedFile;
+        /** Temporary file handle or mapping handle. */
+        PKWFSTEMPFILE       pTempFile;
+    } u;
+} KWMEMMAPPING;
+/** Pointer to a memory mapping tracker. */
+typedef KWMEMMAPPING *PKWMEMMAPPING;
+
 
 /** Pointer to a VirtualAlloc tracker entry. */
 typedef struct KWVIRTALLOC *PKWVIRTALLOC;
@@ -439,6 +582,8 @@ typedef struct KWVIRTALLOC
     PKWVIRTALLOC        pNext;
     void               *pvAlloc;
     KSIZE               cbAlloc;
+    /** This is KU32_MAX if not a preallocated chunk. */
+    KU32                idxPreAllocated;
 } KWVIRTALLOC;
 
 
@@ -557,6 +702,8 @@ typedef struct KWSANDBOX
     int         rcExitCode;
     /** Set if we're running. */
     KBOOL       fRunning;
+    /** Whether to disable caching of ".pch" files. */
+    KBOOL       fNoPchCaching;
 
     /** The command line.   */
     char       *pszCmdLine;
@@ -597,6 +744,17 @@ typedef struct KWSANDBOX
     KU32            cHandles;
     /** Number of active handles in the table. */
     KU32            cActiveHandles;
+    /** Number of handles in the handle table that will not be freed.   */
+    KU32            cFixedHandles;
+    /** Total number of leaked handles. */
+    KU32            cLeakedHandles;
+
+    /** Number of active memory mappings in paMemMappings. */
+    KU32            cMemMappings;
+    /** The allocated size of paMemMappings. */
+    KU32            cMemMappingsAlloc;
+    /** Memory mappings (MapViewOfFile / UnmapViewOfFile). */
+    PKWMEMMAPPING   paMemMappings;
 
     /** Head of the list of temporary file. */
     PKWFSTEMPFILE   pTempFileHead;
@@ -615,7 +773,7 @@ typedef struct KWSANDBOX
      * This is only done from images we forcibly restore.  */
     PKWEXITCALLACK  pExitCallbackHead;
 
-    UNICODE_STRING  SavedCommandLine;
+    MY_UNICODE_STRING SavedCommandLine;
 
 #ifdef WITH_HASH_MD5_CACHE
     /** The special MD5 hash instance. */
@@ -639,11 +797,39 @@ typedef struct KWSANDBOX
     } LastHashRead;
 #endif
 
+#ifdef WITH_CRYPT_CTX_REUSE
+    /** Reusable crypt contexts.  */
+    struct
+    {
+        /** The creation provider type.  */
+        KU32            dwProvType;
+        /** The creation flags. */
+        KU32            dwFlags;
+        /** The length of the container name. */
+        KU32            cwcContainer;
+        /** The length of the provider name. */
+        KU32            cwcProvider;
+        /** The container name string. */
+        wchar_t        *pwszContainer;
+        /** The provider name string. */
+        wchar_t        *pwszProvider;
+        /** The context handle. */
+        HCRYPTPROV      hProv;
+    }                   aCryptCtxs[4];
+    /** Number of reusable crypt conexts in aCryptCtxs. */
+    KU32                cCryptCtxs;
+#endif
+
+
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
-    /** Standard output (and whatever else) line buffer. */
-    KWCONSOLEOUTPUTLINE StdOut;
-    /** Standard error line buffer. */
-    KWCONSOLEOUTPUTLINE StdErr;
+    /** The internal standard output handle. */
+    KWHANDLE            HandleStdOut;
+    /** The internal standard error handle. */
+    KWHANDLE            HandleStdErr;
+    /** Standard output (and whatever else) buffer. */
+    KWOUTPUTSTREAMBUF   StdOut;
+    /** Standard error buffer. */
+    KWOUTPUTSTREAMBUF   StdErr;
     /** Combined buffer of completed lines. */
     KWCONSOLEOUTPUT     Combined;
 #endif
@@ -692,6 +878,9 @@ static KWSANDBOX    g_Sandbox;
 /** The module currently occupying g_abDefLdBuf. */
 static PKWMODULE    g_pModInLdBuf = NULL;
 
+/** The module that previuosly occupied g_abDefLdBuf. */
+static PKWMODULE    g_pModPrevInLdBuf = NULL;
+
 /** Module hash table. */
 static PKWMODULE    g_apModules[127];
 
@@ -708,6 +897,10 @@ static KWGETMODULEHANDLECACHE g_aGetModuleHandleCache[] =
 static PKFSCACHE    g_pFsCache;
 /** The current directory (referenced). */
 static PKFSOBJ      g_pCurDirObj = NULL;
+#ifdef KBUILD_OS_WINDOWS
+/** The windows system32 directory (referenced). */
+static PKFSDIR      g_pWinSys32 = NULL;
+#endif
 
 /** Verbosity level. */
 static int          g_cVerbose = 2;
@@ -715,6 +908,9 @@ static int          g_cVerbose = 2;
 /** Whether we should restart the worker. */
 static KBOOL        g_fRestart = K_FALSE;
 
+/** Whether control-C/SIGINT or Control-Break/SIGBREAK have been seen. */
+static KBOOL volatile g_fCtrlC = K_FALSE;
+
 /* Further down. */
 extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[];
 extern KU32                  const g_cSandboxReplacements;
@@ -722,12 +918,99 @@ extern KU32                  const g_cSandboxReplacements;
 extern KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[];
 extern KU32                  const g_cSandboxNativeReplacements;
 
+extern KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[];
+extern KU32                  const g_cSandboxGetProcReplacements;
+
+
 /** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should
- * cover the default executable link address of 0x400000. */
-#pragma section("DefLdBuf", write, execute, read)
-__declspec(allocate("DefLdBuf"))
+ * cover the default executable link address of 0x400000.
+ * @remarks Early main() makes it read+write+executable.  Attempts as having
+ *          it as a separate section failed because the linker insists on
+ *          writing out every zero in the uninitialized section, resulting in
+ *          really big binaries. */
+__declspec(align(0x1000))
 static KU8          g_abDefLdBuf[16*1024*1024];
 
+#ifdef WITH_LOG_FILE
+/** Log file handle.   */
+static HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
+#endif
+
+
+#ifdef WITH_FIXED_VIRTUAL_ALLOCS
+/** Virtual address space reserved for CL.EXE heap manager.
+ *
+ * Visual C++ 2010 reserves a 78MB chunk of memory from cl.exe at a fixed
+ * address.  It's among other things used for precompiled headers, which
+ * seemingly have addresses hardcoded into them and won't work if mapped
+ * elsewhere.  Thus, we have to make sure the area is available when cl.exe asks
+ * for it.  (The /Zm option may affect this allocation.)
+ */
+static struct
+{
+    /** The memory address we need.   */
+    KUPTR const     uFixed;
+    /** How much we need to fix. */
+    KSIZE const     cbFixed;
+    /** What we actually got, NULL if given back. */
+    void           *pvReserved;
+    /** Whether it is in use or not. */
+    KBOOL           fInUse;
+} g_aFixedVirtualAllocs[] =
+{
+# if K_ARCH == K_ARCH_X86_32
+    /* Visual C++ 2010 reserves 0x04b00000 by default, and Visual C++ 2015 reserves
+       0x05300000.  We get 0x0f000000 to handle large precompiled header files. */
+    { KUPTR_C(        0x11000000), KSIZE_C(        0x0f000000), NULL },
+# else
+    { KUPTR_C(0x000006BB00000000), KSIZE_C(0x000000002EE00000), NULL },
+# endif
+};
+#endif
+
+
+#ifdef WITH_HISTORY
+/** The job history. */
+static char     *g_apszHistory[32];
+/** Index of the next history entry. */
+static unsigned  g_iHistoryNext = 0;
+#endif
+
+
+/** Number of jobs executed. */
+static KU32     g_cJobs;
+/** Number of tools. */
+static KU32     g_cTools;
+/** Number of modules. */
+static KU32     g_cModules;
+/** Number of non-native modules. */
+static KU32     g_cNonNativeModules;
+/** Number of read-cached files. */
+static KU32     g_cReadCachedFiles;
+/** Total size of read-cached files. */
+static KSIZE    g_cbReadCachedFiles;
+
+/** Total number of ReadFile calls. */
+static KSIZE    g_cReadFileCalls;
+/** Total bytes read via ReadFile. */
+static KSIZE    g_cbReadFileTotal;
+/** Total number of read from read-cached files. */
+static KSIZE    g_cReadFileFromReadCached;
+/** Total bytes read from read-cached files. */
+static KSIZE    g_cbReadFileFromReadCached;
+/** Total number of read from in-memory temporary files. */
+static KSIZE    g_cReadFileFromInMemTemp;
+/** Total bytes read from in-memory temporary files. */
+static KSIZE    g_cbReadFileFromInMemTemp;
+
+/** Total number of WriteFile calls. */
+static KSIZE    g_cWriteFileCalls;
+/** Total bytes written via WriteFile. */
+static KSIZE    g_cbWriteFileTotal;
+/** Total number of written to from in-memory temporary files. */
+static KSIZE    g_cWriteFileToInMemTemp;
+/** Total bytes written to in-memory temporary files. */
+static KSIZE    g_cbWriteFileToInMemTemp;
 
 
 /*********************************************************************************************************************************
@@ -735,13 +1018,14 @@ static KU8          g_abDefLdBuf[16*1024*1024];
 *********************************************************************************************************************************/
 static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback;
 static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
-static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle);
+static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle);
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
-static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite);
+static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite);
 #endif
 
 
 
+
 /**
  * Debug printing.
  * @param   pszFormat           Debug format string.
@@ -752,9 +1036,32 @@ static void kwDbgPrintfV(const char *pszFormat, va_list va)
     if (g_cVerbose >= 2)
     {
         DWORD const dwSavedErr = GetLastError();
+#ifdef WITH_LOG_FILE
+        DWORD       dwIgnored;
+        char        szTmp[2048];
+        int         cchPrefix = _snprintf(szTmp, sizeof(szTmp), "%x:%x: ", GetCurrentProcessId(), GetCurrentThreadId());
+        int         cch = vsnprintf(&szTmp[cchPrefix], sizeof(szTmp) - cchPrefix, pszFormat, va);
+        if (cch < (int)sizeof(szTmp) - 1 - cchPrefix)
+            cch += cchPrefix;
+        else
+        {
+            cch = sizeof(szTmp) - 1;
+            szTmp[cch] = '\0';
+        }
+
+        if (g_hLogFile == INVALID_HANDLE_VALUE)
+        {
+            wchar_t wszFilename[128];
+            _snwprintf(wszFilename, K_ELEMENTS(wszFilename), L"kWorker-%x-%x.log", GetTickCount(), GetCurrentProcessId());
+            g_hLogFile = CreateFileW(wszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL /*pSecAttrs*/, CREATE_ALWAYS,
+                                     FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
+        }
 
+        WriteFile(g_hLogFile, szTmp, cch, &dwIgnored, NULL /*pOverlapped*/);
+#else
         fprintf(stderr, "debug: ");
         vfprintf(stderr, pszFormat, va);
+#endif
 
         SetLastError(dwSavedErr);
     }
@@ -1326,8 +1633,8 @@ static void kwLdrModuleRelease(PKWMODULE pMod)
 
         if (!pMod->fNative)
         {
-            kHlpPageFree(pMod->u.Manual.pvCopy, pMod->cbImage);
-            kHlpPageFree(pMod->u.Manual.pvLoad, pMod->cbImage);
+            kHlpPageFree(pMod->u.Manual.pbCopy, pMod->cbImage);
+            kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage);
         }
 
         kHlpFree(pMod);
@@ -1547,6 +1854,7 @@ static PKWMODULE kwLdrModuleCreateForNativekLdrModule(PKLDRMOD pLdrMod, const ch
 
         KW_LOG(("New module: %p LB %#010x %s (native)\n",
                 (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath));
+        g_cModules++;
         return kwLdrModuleLink(pMod);
     }
     return NULL;
@@ -1583,6 +1891,116 @@ static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath, KB
 
 
 /**
+ * Sets up the quick zero & copy tables for the non-native module.
+ *
+ * This is a worker for kwLdrModuleCreateNonNative.
+ *
+ * @param   pMod                The module.
+ */
+static void kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(PKWMODULE pMod)
+{
+    PCKLDRSEG   paSegs = pMod->pLdrMod->aSegments;
+    KU32        cSegs  = pMod->pLdrMod->cSegments;
+    KU32        iSeg;
+
+    KWLDR_LOG(("Setting up quick zero & copy for %s:\n", pMod->pszPath));
+    pMod->u.Manual.cQuickCopyChunks = 0;
+    pMod->u.Manual.cQuickZeroChunks = 0;
+
+    for (iSeg = 0; iSeg < cSegs; iSeg++)
+        switch (paSegs[iSeg].enmProt)
+        {
+            case KPROT_READWRITE:
+            case KPROT_WRITECOPY:
+            case KPROT_EXECUTE_READWRITE:
+            case KPROT_EXECUTE_WRITECOPY:
+                if (paSegs[iSeg].cbMapped)
+                {
+                    KU32 iChunk = pMod->u.Manual.cQuickCopyChunks;
+                    if (iChunk < K_ELEMENTS(pMod->u.Manual.aQuickCopyChunks))
+                    {
+                        /*
+                         * Check for trailing zero words.
+                         */
+                        KSIZE cbTrailingZeros;
+                        if (   paSegs[iSeg].cbMapped >= 64 * 2 * sizeof(KSIZE)
+                            && (paSegs[iSeg].cbMapped & 7) == 0
+                            && pMod->u.Manual.cQuickZeroChunks < K_ELEMENTS(pMod->u.Manual.aQuickZeroChunks) )
+                        {
+                            KSIZE const *pauNatural   = (KSIZE const *)&pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA];
+                            KSIZE        cNatural     = paSegs[iSeg].cbMapped / sizeof(KSIZE);
+                            KSIZE        idxFirstZero = cNatural;
+                            while (idxFirstZero > 0)
+                                if (pauNatural[--idxFirstZero] == 0)
+                                { /* likely */ }
+                                else
+                                {
+                                    idxFirstZero++;
+                                    break;
+                                }
+                            cbTrailingZeros = (cNatural - idxFirstZero) * sizeof(KSIZE);
+                            if (cbTrailingZeros < 128)
+                                cbTrailingZeros = 0;
+                        }
+                        else
+                            cbTrailingZeros = 0;
+
+                        /*
+                         * Add quick copy entry.
+                         */
+                        if (cbTrailingZeros < paSegs[iSeg].cbMapped)
+                        {
+                            pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst    = &pMod->u.Manual.pbLoad[(KSIZE)paSegs[iSeg].RVA];
+                            pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc    = &pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA];
+                            pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy = paSegs[iSeg].cbMapped - cbTrailingZeros;
+                            pMod->u.Manual.cQuickCopyChunks = iChunk + 1;
+                            KWLDR_LOG(("aQuickCopyChunks[%u]: %#p LB %#" KSIZE_PRI " <- %p (%*.*s)\n", iChunk,
+                                       pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst,
+                                       pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy,
+                                       pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc,
+                                       paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName));
+                        }
+
+                        /*
+                         * Add quick zero entry.
+                         */
+                        if (cbTrailingZeros)
+                        {
+                            KU32 iZero = pMod->u.Manual.cQuickZeroChunks;
+                            pMod->u.Manual.aQuickZeroChunks[iZero].pbDst    = pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst
+                                                                            + pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy;
+                            pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero = cbTrailingZeros;
+                            pMod->u.Manual.cQuickZeroChunks = iZero + 1;
+                            KWLDR_LOG(("aQuickZeroChunks[%u]: %#p LB %#" KSIZE_PRI " <- zero (%*.*s)\n", iZero,
+                                       pMod->u.Manual.aQuickZeroChunks[iZero].pbDst,
+                                       pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero,
+                                       paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName));
+                        }
+                    }
+                    else
+                    {
+                        /*
+                         * We're out of quick copy table entries, so just copy the whole darn thing.
+                         * We cannot 104% guarantee that the segments are in mapping order, so this is simpler.
+                         */
+                        kHlpAssertFailed();
+                        pMod->u.Manual.aQuickCopyChunks[0].pbDst    = pMod->u.Manual.pbLoad;
+                        pMod->u.Manual.aQuickCopyChunks[0].pbSrc    = pMod->u.Manual.pbCopy;
+                        pMod->u.Manual.aQuickCopyChunks[0].cbToCopy = pMod->cbImage;
+                        pMod->u.Manual.cQuickCopyChunks = 1;
+                        KWLDR_LOG(("Quick copy not possible!\n"));
+                        return;
+                    }
+                }
+                break;
+
+            default:
+                break;
+        }
+}
+
+
+/**
  * Creates a module using the our own loader.
  *
  * @returns Module w/ 1 reference on success, NULL on failure.
@@ -1647,10 +2065,13 @@ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath,
                     pMod->fNative       = K_FALSE;
                     pMod->pLdrMod       = pLdrMod;
                     pMod->u.Manual.cImpMods = (KU32)cImports;
-                    pMod->u.Manual.fUseLdBuf = K_FALSE;
 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
                     pMod->u.Manual.fRegisteredFunctionTable = K_FALSE;
 #endif
+                    pMod->u.Manual.fUseLdBuf = K_FALSE;
+                    pMod->u.Manual.fCanDoQuick = K_FALSE;
+                    pMod->u.Manual.cQuickZeroChunks = 0;
+                    pMod->u.Manual.cQuickCopyChunks = 0;
                     pMod->pszPath       = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath);
                     pMod->pwszPath      = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
                     kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
@@ -1660,32 +2081,31 @@ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath,
                      */
                     fFixed = pLdrMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
                           || pLdrMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
-                    pMod->u.Manual.pvLoad = fFixed ? (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL;
+                    pMod->u.Manual.pbLoad = fFixed ? (KU8 *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL;
                     pMod->cbImage = (KSIZE)kLdrModSize(pLdrMod);
                     if (   !fFixed
                         || pLdrMod->enmType != KLDRTYPE_EXECUTABLE_FIXED /* only allow fixed executables */
-                        || (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf)
-                        || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf < pMod->cbImage)
-                        rc = kHlpPageAlloc(&pMod->u.Manual.pvLoad, pMod->cbImage, KPROT_EXECUTE_READWRITE, fFixed);
+                        || (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf)
+                        || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf < pMod->cbImage)
+                        rc = kHlpPageAlloc((void **)&pMod->u.Manual.pbLoad, pMod->cbImage, KPROT_EXECUTE_READWRITE, fFixed);
                     else
                         pMod->u.Manual.fUseLdBuf = K_TRUE;
                     if (rc == 0)
                     {
-                        rc = kHlpPageAlloc(&pMod->u.Manual.pvCopy, pMod->cbImage, KPROT_READWRITE, K_FALSE);
+                        rc = kHlpPageAlloc(&pMod->u.Manual.pbCopy, pMod->cbImage, KPROT_READWRITE, K_FALSE);
                         if (rc == 0)
                         {
-
                             KI32 iImp;
 
                             /*
                              * Link the module (unless it's an executable image) and process the imports.
                              */
-                            pMod->hOurMod = (HMODULE)pMod->u.Manual.pvLoad;
+                            pMod->hOurMod = (HMODULE)pMod->u.Manual.pbLoad;
                             if (!fExe)
                                 kwLdrModuleLink(pMod);
                             KW_LOG(("New module: %p LB %#010x %s (kLdr)\n",
-                                    pMod->u.Manual.pvLoad, pMod->cbImage, pMod->pszPath));
-                            kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pvLoad);
+                                    pMod->u.Manual.pbLoad, pMod->cbImage, pMod->pszPath));
+                            kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad);
 
                             for (iImp = 0; iImp < cImports; iImp++)
                             {
@@ -1702,7 +2122,7 @@ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath,
 
                             if (rc == 0)
                             {
-                                rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pvCopy, (KUPTR)pMod->u.Manual.pvLoad,
+                                rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pbCopy, (KUPTR)pMod->u.Manual.pbLoad,
                                                     kwLdrModuleGetImportCallback, pMod);
                                 if (rc == 0)
                                 {
@@ -1711,7 +2131,7 @@ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath,
                                      * Find the function table.  No validation here because the
                                      * loader did that already, right...
                                      */
-                                    KU8                        *pbImg = (KU8 *)pMod->u.Manual.pvCopy;
+                                    KU8                        *pbImg = (KU8 *)pMod->u.Manual.pbCopy;
                                     IMAGE_NT_HEADERS const     *pNtHdrs;
                                     IMAGE_DATA_DIRECTORY const *pXcptDir;
                                     if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE)
@@ -1734,11 +2154,15 @@ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath,
                                     }
 #endif
 
+                                    kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(pMod);
+
                                     /*
                                      * Final finish.
                                      */
-                                    pMod->u.Manual.pvBits = pMod->u.Manual.pvCopy;
+                                    pMod->u.Manual.pvBits = pMod->u.Manual.pbCopy;
                                     pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
+                                    g_cModules++;
+                                    g_cNonNativeModules++;
                                     return pMod;
                                 }
                             }
@@ -1747,7 +2171,7 @@ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath,
                             return NULL;
                         }
 
-                        kHlpPageFree(pMod->u.Manual.pvLoad, pMod->cbImage);
+                        kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage);
                         kwErrPrintf("Failed to allocate %#x bytes\n", pMod->cbImage);
                     }
                     else if (fFixed)
@@ -1781,7 +2205,7 @@ static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbo
                                 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
                                 puValue, pfKind);
     else
-        rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pvLoad,
+        rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pbLoad,
                                 iSymbol, pchSymbol, cchSymbol, pszVersion,
                                 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
                                 puValue, pfKind);
@@ -1822,7 +2246,7 @@ static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbo
 static int kwLdrModuleQueryMainEntrypoint(PKWMODULE pMod, KUPTR *puAddrMain)
 {
     KLDRADDR uLdrAddrMain;
-    int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod,  pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pvLoad, &uLdrAddrMain);
+    int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod, pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pbLoad, &uLdrAddrMain);
     if (rc == 0)
     {
         *puAddrMain = (KUPTR)uLdrAddrMain;
@@ -1850,18 +2274,75 @@ static KBOOL kwLdrModuleShouldDoNativeReplacements(const char *pszFilename, KWLO
 
 
 /**
+ * Lazily initializes the g_pWinSys32 variable.
+ */
+static PKFSDIR kwLdrResolveWinSys32(void)
+{
+    KFSLOOKUPERROR  enmError;
+    PKFSDIR         pWinSys32;
+
+    /* Get the path first. */
+    char            szSystem32[MAX_PATH];
+    if (GetSystemDirectoryA(szSystem32, sizeof(szSystem32)) >= sizeof(szSystem32))
+    {
+        kwErrPrintf("GetSystemDirectory failed: %u\n", GetLastError());
+        strcpy(szSystem32, "C:\\Windows\\System32");
+    }
+
+    /* Look it up and verify it. */
+    pWinSys32 = (PKFSDIR)kFsCacheLookupA(g_pFsCache, szSystem32, &enmError);
+    if (pWinSys32)
+    {
+        if (pWinSys32->Obj.bObjType == KFSOBJ_TYPE_DIR)
+        {
+            g_pWinSys32 = pWinSys32;
+            return pWinSys32;
+        }
+
+        kwErrPrintf("System directory '%s' isn't of 'DIR' type: %u\n", szSystem32, g_pWinSys32->Obj.bObjType);
+    }
+    else
+        kwErrPrintf("Failed to lookup system directory '%s': %u\n", szSystem32, enmError);
+    return NULL;
+}
+
+
+/**
  * Whether we can load this DLL natively or not.
  *
  * @returns K_TRUE/K_FALSE.
  * @param   pszFilename         The filename (no path).
  * @param   enmLocation         The location.
+ * @param   pszFullPath         The full filename and path.
  */
-static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation)
+static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation, const char *pszFullPath)
 {
     if (enmLocation == KWLOCATION_SYSTEM32)
         return K_TRUE;
     if (enmLocation == KWLOCATION_UNKNOWN_NATIVE)
         return K_TRUE;
+
+    /* If the location is unknown, we must check if it's some dynamic loading
+       of a SYSTEM32 DLL with a full path.  We do not want to load these ourselves! */
+    if (enmLocation == KWLOCATION_UNKNOWN)
+    {
+        PKFSDIR pWinSys32 = g_pWinSys32;
+        if (!pWinSys32)
+            pWinSys32 = kwLdrResolveWinSys32();
+        if (pWinSys32)
+        {
+            KFSLOOKUPERROR enmError;
+            PKFSOBJ pFsObj = kFsCacheLookupA(g_pFsCache, pszFullPath, &enmError);
+            if (pFsObj)
+            {
+                KBOOL fInWinSys32 = pFsObj->pParent == pWinSys32;
+                kFsCacheObjRelease(g_pFsCache, pFsObj);
+                if (fInWinSys32)
+                    return K_TRUE;
+            }
+        }
+    }
+
     return kHlpStrNICompAscii(pszFilename, TUPLE("msvc"))   == 0
         || kHlpStrNICompAscii(pszFilename, TUPLE("msdis"))  == 0
         || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb"))  == 0;
@@ -1954,7 +2435,7 @@ static PKWMODULE kwLdrModuleTryLoadDll(const char *pszPath, KWLOCATION enmLocati
              * Not in the hash table, so we have to load it from scratch.
              */
             pszName = kHlpGetFilename(szNormPath);
-            if (kwLdrModuleCanLoadNatively(pszName, enmLocation))
+            if (kwLdrModuleCanLoadNatively(pszName, enmLocation, szNormPath))
                 pMod = kwLdrModuleCreateNative(szNormPath, uHashPath,
                                                kwLdrModuleShouldDoNativeReplacements(pszName, enmLocation));
             else
@@ -2054,7 +2535,9 @@ static int kwLdrModuleInitTree(PKWMODULE pMod)
     int rc = 0;
     if (!pMod->fNative)
     {
-        /* Need to copy bits? */
+        /*
+         * Need to copy bits?
+         */
         if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_BITS)
         {
             if (pMod->u.Manual.fUseLdBuf)
@@ -2066,29 +2549,69 @@ static int kwLdrModuleInitTree(PKWMODULE pMod)
                     kHlpAssert(fRc); K_NOREF(fRc);
                 }
 #endif
+                g_pModPrevInLdBuf = g_pModInLdBuf;
                 g_pModInLdBuf = pMod;
             }
 
-            kHlpMemCopy(pMod->u.Manual.pvLoad, pMod->u.Manual.pvCopy, pMod->cbImage);
+            /* Do quick zeroing and copying when we can. */
+            pMod->u.Manual.fCanDoQuick = K_FALSE;
+            if (   pMod->u.Manual.fCanDoQuick
+                && (   !pMod->u.Manual.fUseLdBuf
+                    || g_pModPrevInLdBuf == pMod))
+            {
+                /* Zero first. */
+                kHlpAssert(pMod->u.Manual.cQuickZeroChunks <= 3);
+                switch (pMod->u.Manual.cQuickZeroChunks)
+                {
+                    case 3: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[2].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[2].cbToZero);
+                    case 2: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[1].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[1].cbToZero);
+                    case 1: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[0].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[0].cbToZero);
+                    case 0: break;
+                }
+
+                /* Then copy. */
+                kHlpAssert(pMod->u.Manual.cQuickCopyChunks > 0);
+                kHlpAssert(pMod->u.Manual.cQuickCopyChunks <= 3);
+                switch (pMod->u.Manual.cQuickCopyChunks)
+                {
+                    case 3: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[2].pbDst, pMod->u.Manual.aQuickCopyChunks[2].pbSrc,
+                                        pMod->u.Manual.aQuickCopyChunks[2].cbToCopy);
+                    case 2: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[1].pbDst, pMod->u.Manual.aQuickCopyChunks[1].pbSrc,
+                                        pMod->u.Manual.aQuickCopyChunks[1].cbToCopy);
+                    case 1: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[0].pbDst, pMod->u.Manual.aQuickCopyChunks[0].pbSrc,
+                                        pMod->u.Manual.aQuickCopyChunks[0].cbToCopy);
+                    case 0: break;
+                }
+            }
+            /* Must copy the whole image. */
+            else
+            {
+                kHlpMemCopy(pMod->u.Manual.pbLoad, pMod->u.Manual.pbCopy, pMod->cbImage);
+                pMod->u.Manual.fCanDoQuick = K_TRUE;
+            }
             pMod->u.Manual.enmState = KWMODSTATE_NEEDS_INIT;
         }
 
 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
-        /* Need to register function table? */
+        /*
+         * Need to register function table?
+         */
         if (   !pMod->u.Manual.fRegisteredFunctionTable
             && pMod->u.Manual.cFunctions > 0)
         {
             pMod->u.Manual.fRegisteredFunctionTable = RtlAddFunctionTable(pMod->u.Manual.paFunctions,
                                                                           pMod->u.Manual.cFunctions,
-                                                                          (KUPTR)pMod->u.Manual.pvLoad) != FALSE;
+                                                                          (KUPTR)pMod->u.Manual.pbLoad) != FALSE;
             kHlpAssert(pMod->u.Manual.fRegisteredFunctionTable);
         }
 #endif
 
         if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT)
         {
-            /* Must do imports first, but mark our module as being initialized to avoid
-               endless recursion should there be a dependency loop. */
+            /*
+             * Must do imports first, but mark our module as being initialized to avoid
+             * endless recursion should there be a dependency loop.
+             */
             KSIZE iImp;
             pMod->u.Manual.enmState = KWMODSTATE_BEING_INITED;
 
@@ -2099,7 +2622,7 @@ static int kwLdrModuleInitTree(PKWMODULE pMod)
                     return rc;
             }
 
-            rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pvLoad, (KUPTR)pMod->u.Manual.pvLoad);
+            rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod);
             if (rc == 0)
                 pMod->u.Manual.enmState = KWMODSTATE_READY;
             else
@@ -2350,6 +2873,7 @@ static PKWTOOL kwToolEntryCreate(PKFSOBJ pToolFsObj)
             pTool->enmType = KWTOOLTYPE_EXEC;
 
         kFsCacheObjRelease(g_pFsCache, pToolFsObj);
+        g_cTools++;
         return pTool;
     }
     kFsCacheObjRelease(g_pFsCache, pToolFsObj);
@@ -2402,6 +2926,76 @@ static PKWTOOL kwToolLookup(const char *pszExe)
  */
 
 
+/**
+ * This is for kDep.
+ */
+int kwFsPathExists(const char *pszPath)
+{
+    BirdTimeSpec_T  TsIgnored;
+    KFSLOOKUPERROR  enmError;
+    PKFSOBJ         pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszPath, &enmError);
+    if (pFsObj)
+    {
+        kFsCacheObjRelease(g_pFsCache, pFsObj);
+        return 1;
+    }
+    return birdStatModTimeOnly(pszPath, &TsIgnored, 1) == 0;
+}
+
+
+/* duplicated in dir-nt-bird.c */
+void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
+{
+    KFSLOOKUPERROR  enmError;
+    PKFSOBJ         pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
+    if (pPathObj)
+    {
+        KSIZE off = pPathObj->cchParent;
+        if (off > 0)
+        {
+            KSIZE offEnd = off + pPathObj->cchName;
+            if (offEnd < cbFull)
+            {
+                PKFSDIR pAncestor;
+
+                pszFull[off + pPathObj->cchName] = '\0';
+                memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName);
+
+                for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
+                {
+                    kHlpAssert(off > 1);
+                    kHlpAssert(pAncestor != NULL);
+                    kHlpAssert(pAncestor->Obj.cchName > 0);
+                    pszFull[--off] = '/';
+                    off -= pAncestor->Obj.cchName;
+                    kHlpAssert(pAncestor->Obj.cchParent == off);
+                    memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName);
+                }
+                kFsCacheObjRelease(g_pFsCache, pPathObj);
+                return;
+            }
+        }
+        else
+        {
+            if ((size_t)pPathObj->cchName + 1 < cbFull)
+            {
+                memcpy(pszFull, pPathObj->pszName, pPathObj->cchName);
+                pszFull[pPathObj->cchName] = '/';
+                pszFull[pPathObj->cchName + 1] = '\0';
+
+                kFsCacheObjRelease(g_pFsCache, pPathObj);
+                return;
+            }
+        }
+
+        /* do fallback. */
+        kHlpAssertFailed();
+        kFsCacheObjRelease(g_pFsCache, pPathObj);
+    }
+
+    nt_fullpath(pszPath, pszFull, cbFull);
+}
+
 
 /**
  * Helper for getting the extension of a UTF-16 path.
@@ -2637,7 +3231,7 @@ static void __cdecl kwSandbox_msvcrt_terminate(void)
 /** CRT - _onexit   */
 static _onexit_t __cdecl kwSandbox_msvcrt__onexit(_onexit_t pfnFunc)
 {
-    if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
+    //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
     {
         PKWEXITCALLACK pCallback;
         KW_LOG(("_onexit(%p)\n", pfnFunc));
@@ -2662,7 +3256,7 @@ static _onexit_t __cdecl kwSandbox_msvcrt__onexit(_onexit_t pfnFunc)
 /** CRT - atexit   */
 static int __cdecl kwSandbox_msvcrt_atexit(int (__cdecl *pfnFunc)(void))
 {
-    if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
+    //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
     {
         PKWEXITCALLACK pCallback;
         kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
@@ -3026,7 +3620,6 @@ static int kwSandboxGrowEnv(PKWSANDBOX pSandbox, KSIZE cMin)
     while (cNew < cMin)
         cNew += 256;
 
-
     pvNew = kHlpRealloc(pSandbox->environ, cNew * sizeof(pSandbox->environ[0]));
     if (pvNew)
     {
@@ -3968,6 +4561,69 @@ static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3,
 }
 
 
+#ifndef NDEBUG
+/*
+ * This wraps up to three InvokeCompilerPassW functions and dumps their arguments to the log.
+ */
+# if K_ARCH == K_ARCH_X86_32
+static char g_szInvokeCompilePassW[] = "_InvokeCompilerPassW at 16";
+# else
+static char g_szInvokeCompilePassW[] = "InvokeCompilerPassW";
+# endif
+typedef KIPTR __stdcall FNINVOKECOMPILERPASSW(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance);
+typedef FNINVOKECOMPILERPASSW *PFNINVOKECOMPILERPASSW;
+typedef struct KWCXINTERCEPTORENTRY
+{
+    PFNINVOKECOMPILERPASSW  pfnOrg;
+    PKWMODULE               pModule;
+    PFNINVOKECOMPILERPASSW  pfnWrap;
+} KWCXINTERCEPTORENTRY;
+
+static KIPTR kwSandbox_Cx_InvokeCompilerPassW_Common(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance,
+                                                     KWCXINTERCEPTORENTRY *pEntry)
+{
+    int i;
+    KIPTR rcExit;
+    KW_LOG(("%s!InvokeCompilerPassW(%d, %p, %#x, %p)\n",
+            &pEntry->pModule->pszPath[pEntry->pModule->offFilename], cArgs, papwszArgs, fFlags, phCluiInstance));
+    for (i = 0; i < cArgs; i++)
+        KW_LOG((" papwszArgs[%u]='%ls'\n", i, papwszArgs[i]));
+
+    rcExit = pEntry->pfnOrg(cArgs, papwszArgs, fFlags, phCluiInstance);
+
+    KW_LOG(("%s!InvokeCompilerPassW returns %d\n", &pEntry->pModule->pszPath[pEntry->pModule->offFilename], rcExit));
+    return rcExit;
+}
+
+static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_0;
+static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_1;
+static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_2;
+
+static KWCXINTERCEPTORENTRY g_aCxInterceptorEntries[] =
+{
+    { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_0 },
+    { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_1 },
+    { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_2 },
+};
+
+static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_0(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance)
+{
+    return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[0]);
+}
+
+static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_1(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance)
+{
+    return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[1]);
+}
+
+static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_2(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance)
+{
+    return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[2]);
+}
+
+#endif /* !NDEBUG */
+
+
 /** Kernel32 - GetProcAddress()   */
 static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc)
 {
@@ -3984,7 +4640,7 @@ static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR psz
         KLDRADDR uValue;
         int rc = kLdrModQuerySymbol(pMod->pLdrMod,
                                     pMod->fNative ? NULL : pMod->u.Manual.pvBits,
-                                    pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pvLoad,
+                                    pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pbLoad,
                                     KU32_MAX /*iSymbol*/,
                                     pszProc,
                                     kHlpStrLen(pszProc),
@@ -3994,15 +4650,60 @@ static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR psz
                                     NULL /*pfKind*/);
         if (rc == 0)
         {
-            static int s_cDbgGets = 0;
-            s_cDbgGets++;
-            KW_LOG(("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets));
-            kwLdrModuleRelease(pMod);
-            //if (s_cGets >= 3)
-            //    return (FARPROC)kwSandbox_BreakIntoDebugger;
-            return (FARPROC)(KUPTR)uValue;
-        }
-
+            //static int s_cDbgGets = 0;
+            KU32 cchProc = (KU32)kHlpStrLen(pszProc);
+            KU32 i = g_cSandboxGetProcReplacements;
+            while (i-- > 0)
+                if (   g_aSandboxGetProcReplacements[i].cchFunction == cchProc
+                    && kHlpMemComp(g_aSandboxGetProcReplacements[i].pszFunction, pszProc, cchProc) == 0)
+                {
+                    if (   !g_aSandboxGetProcReplacements[i].pszModule
+                        || kHlpStrICompAscii(g_aSandboxGetProcReplacements[i].pszModule, &pMod->pszPath[pMod->offFilename]) == 0)
+                    {
+                        if (   !g_aSandboxGetProcReplacements[i].fOnlyExe
+                            || (KUPTR)_ReturnAddress() - (KUPTR)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod
+                               < g_Sandbox.pTool->u.Sandboxed.pExe->cbImage)
+                        {
+                            uValue = g_aSandboxGetProcReplacements[i].pfnReplacement;
+                            KW_LOG(("GetProcAddress(%s, %s) -> %p replaced\n", pMod->pszPath, pszProc, (KUPTR)uValue));
+                        }
+                        kwLdrModuleRelease(pMod);
+                        return (FARPROC)(KUPTR)uValue;
+                    }
+                }
+
+#ifndef NDEBUG
+            /* Intercept the compiler pass method, dumping arguments. */
+            if (kHlpStrComp(pszProc, g_szInvokeCompilePassW) == 0)
+            {
+                KU32 i;
+                for (i = 0; i < K_ELEMENTS(g_aCxInterceptorEntries); i++)
+                    if ((KUPTR)g_aCxInterceptorEntries[i].pfnOrg == uValue)
+                    {
+                        uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap;
+                        KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW\n"));
+                        break;
+                    }
+                if (i >= K_ELEMENTS(g_aCxInterceptorEntries))
+                    while (i-- > 0)
+                        if (g_aCxInterceptorEntries[i].pfnOrg == NULL)
+                        {
+                            g_aCxInterceptorEntries[i].pfnOrg  = (PFNINVOKECOMPILERPASSW)(KUPTR)uValue;
+                            g_aCxInterceptorEntries[i].pModule = pMod;
+                            uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap;
+                            KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW (new)\n"));
+                            break;
+                        }
+            }
+#endif
+            KW_LOG(("GetProcAddress(%s, %s) -> %p\n", pMod->pszPath, pszProc, (KUPTR)uValue));
+            kwLdrModuleRelease(pMod);
+            //s_cDbgGets++;
+            //if (s_cGets >= 3)
+            //    return (FARPROC)kwSandbox_BreakIntoDebugger;
+            return (FARPROC)(KUPTR)uValue;
+        }
+
         KWFS_TODO();
         SetLastError(ERROR_PROC_NOT_FOUND);
         kwLdrModuleRelease(pMod);
@@ -4244,11 +4945,12 @@ static HANDLE kwFsTempFileCreateHandle(PKWFSTEMPFILE pTempFile, DWORD dwDesiredA
         if (pHandle)
         {
             pHandle->enmType            = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING;
+            pHandle->cRefs              = 1;
             pHandle->offFile            = 0;
             pHandle->hHandle            = hFile;
             pHandle->dwDesiredAccess    = dwDesiredAccess;
             pHandle->u.pTempFile        = pTempFile;
-            if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
+            if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, hFile))
             {
                 pTempFile->cActiveHandles++;
                 kHlpAssert(pTempFile->cActiveHandles >= 1);
@@ -4386,104 +5088,147 @@ static HANDLE kwFsTempFileCreateW(const wchar_t *pwszFilename, DWORD dwDesiredAc
 
 #endif /* WITH_TEMP_MEMORY_FILES */
 
-
 /**
- * Checks if the file extension indicates that the file/dir is something we
- * ought to cache.
+ * Worker for kwFsIsCacheableExtensionA and kwFsIsCacheableExtensionW
  *
- * @returns K_TRUE if cachable, K_FALSE if not.
- * @param   pszExt              The kHlpGetExt result.
+ * @returns K_TRUE if cacheable, K_FALSE if not.
+ * @param   wcFirst             The first extension character.
+ * @param   wcSecond            The second extension character.
+ * @param   wcThird             The third extension character.
  * @param   fAttrQuery          Set if it's for an attribute query, clear if for
  *                              file creation.
  */
-static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery)
+static KBOOL kwFsIsCacheableExtensionCommon(wchar_t wcFirst, wchar_t wcSecond, wchar_t wcThird, KBOOL fAttrQuery)
 {
-    char const chFirst = *pszExt;
-
     /* C++ header without an extension or a directory. */
-    if (chFirst == '\0')
+    if (wcFirst == '\0')
     {
         /** @todo exclude temporary files...  */
         return K_TRUE;
     }
 
     /* C Header: .h */
-    if (chFirst == 'h' || chFirst == 'H')
+    if (wcFirst == 'h' || wcFirst == 'H')
     {
-        char        chThird;
-        char const  chSecond = pszExt[1];
-        if (chSecond == '\0')
+        if (wcSecond == '\0')
             return K_TRUE;
-        chThird = pszExt[2];
 
         /* C++ Header: .hpp, .hxx */
-        if (   (chSecond == 'p' || chSecond == 'P')
-            && (chThird  == 'p' || chThird  == 'P')
-            && pszExt[3] == '\0')
+        if (   (wcSecond == 'p' || wcSecond == 'P')
+            && (wcThird  == 'p' || wcThird  == 'P'))
             return K_TRUE;
-        if (   (chSecond == 'x' || chSecond == 'X')
-            && (chThird  == 'x' || chThird  == 'X')
-            && pszExt[3] == '\0')
+        if (   (wcSecond == 'x' || wcSecond == 'X')
+            && (wcThird  == 'x' || wcThird  == 'X'))
             return K_TRUE;
     }
     /* Misc starting with i. */
-    else if (chFirst == 'i' || chFirst == 'I')
+    else if (wcFirst == 'i' || wcFirst == 'I')
     {
-        char const chSecond = pszExt[1];
-        if (chSecond != '\0')
+        if (wcSecond != '\0')
         {
-            if (chSecond == 'n' || chSecond == 'N')
+            if (wcSecond == 'n' || wcSecond == 'N')
             {
-                char const chThird = pszExt[2];
-
                 /* C++ inline header: .inl */
-                if (   (chThird == 'l' || chThird == 'L')
-                    && pszExt[3] == '\0')
+                if (wcThird == 'l' || wcThird == 'L')
                     return K_TRUE;
 
                 /* Assembly include file: .inc */
-                if (   (chThird == 'c' || chThird == 'C')
-                    && pszExt[3] == '\0')
+                if (wcThird == 'c' || wcThird == 'C')
                     return K_TRUE;
             }
         }
     }
     /* Assembly header: .mac */
-    else if (chFirst == 'm' || chFirst == 'M')
+    else if (wcFirst == 'm' || wcFirst == 'M')
+    {
+        if (wcSecond == 'a' || wcSecond == 'A')
+        {
+            if (wcThird == 'c' || wcThird == 'C')
+                return K_TRUE;
+        }
+    }
+#ifdef WITH_PCH_CACHING
+    /* Precompiled header: .pch */
+    else if (wcFirst == 'p' || wcFirst == 'P')
+    {
+        if (wcSecond == 'c' || wcSecond == 'C')
+        {
+            if (wcThird == 'h' || wcThird == 'H')
+                return !g_Sandbox.fNoPchCaching;
+        }
+    }
+#endif
+#if 0 /* Experimental - need to flush these afterwards as they're highly unlikely to be used after the link is done.  */
+    /* Linker - Object file: .obj */
+    if ((wcFirst == 'o' || wcFirst == 'O') && g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
     {
-        char const  chSecond = pszExt[1];
-        if (chSecond == 'a' || chSecond == 'A')
+        if (wcSecond == 'b' || wcSecond == 'B')
         {
-            char const chThird = pszExt[2];
-            if (  (chThird == 'c' || chThird == 'C')
-                && pszExt[3] == '\0')
+            if (wcThird == 'j' || wcThird == 'J')
                 return K_TRUE;
         }
     }
+#endif
     else if (fAttrQuery)
     {
         /* Dynamic link library: .dll */
-        if (chFirst == 'd' || chFirst == 'D')
+        if (wcFirst == 'd' || wcFirst == 'D')
         {
-            char const chSecond = pszExt[1];
-            if (chSecond == 'l' || chSecond == 'L')
+            if (wcSecond == 'l' || wcSecond == 'L')
             {
-                char const chThird = pszExt[2];
-                if (chThird == 'l' || chThird == 'L')
+                if (wcThird == 'l' || wcThird == 'L')
                     return K_TRUE;
             }
         }
         /* Executable file: .exe */
-        else if (chFirst == 'e' || chFirst == 'E')
+        else if (wcFirst == 'e' || wcFirst == 'E')
         {
-            char const chSecond = pszExt[1];
-            if (chSecond == 'x' || chSecond == 'X')
+            if (wcSecond == 'x' || wcSecond == 'X')
             {
-                char const chThird = pszExt[2];
-                if (chThird == 'e' || chThird == 'e')
+                if (wcThird == 'e' || wcThird == 'E')
                     return K_TRUE;
             }
         }
+        /* Response file: .rsp */
+        else if (wcFirst == 'r' || wcFirst == 'R')
+        {
+            if (wcSecond == 's' || wcSecond == 'S')
+            {
+                if (wcThird == 'p' || wcThird == 'P')
+                    return !g_Sandbox.fNoPchCaching;
+            }
+        }
+        /* Linker: */
+        if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
+        {
+            /* Object file: .obj */
+            if (wcFirst == 'o' || wcFirst == 'O')
+            {
+                if (wcSecond == 'b' || wcSecond == 'B')
+                {
+                    if (wcThird == 'j' || wcThird == 'J')
+                        return K_TRUE;
+                }
+            }
+            /* Library file: .lib */
+            else if (wcFirst == 'l' || wcFirst == 'L')
+            {
+                if (wcSecond == 'i' || wcSecond == 'I')
+                {
+                    if (wcThird == 'b' || wcThird == 'B')
+                        return K_TRUE;
+                }
+            }
+            /* Linker definition file: .def */
+            else if (wcFirst == 'd' || wcFirst == 'D')
+            {
+                if (wcSecond == 'e' || wcSecond == 'E')
+                {
+                    if (wcThird == 'f' || wcThird == 'F')
+                        return K_TRUE;
+                }
+            }
+        }
     }
 
     return K_FALSE;
@@ -4491,6 +5236,34 @@ static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery)
 
 
 /**
+ * Checks if the file extension indicates that the file/dir is something we
+ * ought to cache.
+ *
+ * @returns K_TRUE if cachable, K_FALSE if not.
+ * @param   pszExt              The kHlpGetExt result.
+ * @param   fAttrQuery          Set if it's for an attribute query, clear if for
+ *                              file creation.
+ */
+static KBOOL kwFsIsCacheableExtensionA(const char *pszExt, KBOOL fAttrQuery)
+{
+    wchar_t const wcFirst = *pszExt;
+    if (wcFirst)
+    {
+        wchar_t const wcSecond = pszExt[1];
+        if (wcSecond)
+        {
+            wchar_t const wcThird = pszExt[2];
+            if (pszExt[3] == '\0')
+                return kwFsIsCacheableExtensionCommon(wcFirst, wcSecond, wcThird, fAttrQuery);
+            return K_FALSE;
+        }
+        return kwFsIsCacheableExtensionCommon(wcFirst, 0, 0, fAttrQuery);
+    }
+    return kwFsIsCacheableExtensionCommon(0, 0, 0, fAttrQuery);
+}
+
+
+/**
  * Checks if the extension of the given UTF-16 path indicates that the file/dir
  * should be cached.
  *
@@ -4499,25 +5272,16 @@ static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery)
  * @param   fAttrQuery          Set if it's for an attribute query, clear if for
  *                              file creation.
  */
-static KBOOL kwFsIsCachablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery)
+static KBOOL kwFsIsCacheablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery)
 {
-    /*
-     * Extract the extension, check that it's in the applicable range, roughly
-     * convert it to ASCII/ANSI, and feed it to kwFsIsCachableExtensionA for
-     * the actual check.  This avoids a lot of code duplication.
-     */
-    wchar_t         wc;
-    char            szExt[4];
     KSIZE           cwcExt;
     wchar_t const  *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt);
     switch (cwcExt)
     {
-        case 3: if ((wchar_t)(szExt[2] = (char)(wc = pwszExt[2])) == wc) { /*likely*/ } else break;
-        case 2: if ((wchar_t)(szExt[1] = (char)(wc = pwszExt[1])) == wc) { /*likely*/ } else break;
-        case 1: if ((wchar_t)(szExt[0] = (char)(wc = pwszExt[0])) == wc) { /*likely*/ } else break;
-        case 0:
-            szExt[cwcExt] = '\0';
-            return kwFsIsCachableExtensionA(szExt, fAttrQuery);
+        case 3: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], pwszExt[2], fAttrQuery);
+        case 2: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], 0,          fAttrQuery);
+        case 1: return kwFsIsCacheableExtensionCommon(pwszExt[0], 0,          0,          fAttrQuery);
+        case 0: return kwFsIsCacheableExtensionCommon(0,          0,          0,          fAttrQuery);
     }
     return K_FALSE;
 }
@@ -4576,50 +5340,55 @@ static PKFSWCACHEDFILE kwFsObjCacheNewFile(PKFSOBJ pFsObj)
         if (GetFileSizeEx(hFile, &cbFile))
         {
             if (   cbFile.QuadPart >= 0
-                && cbFile.QuadPart < 16*1024*1024)
+#ifdef WITH_PCH_CACHING
+                && (   cbFile.QuadPart < 16*1024*1024
+                    || (   cbFile.QuadPart < 96*1024*1024
+                        && pFsObj->cchName > 4
+                        && !g_Sandbox.fNoPchCaching
+                        && kHlpStrICompAscii(&pFsObj->pszName[pFsObj->cchName - 4], ".pch") == 0) )
+#endif
+               )
             {
                 KU32 cbCache = (KU32)cbFile.QuadPart;
-                KU8 *pbCache = (KU8 *)kHlpAlloc(cbCache);
-                if (pbCache)
+                HANDLE hMapping = CreateFileMappingW(hFile, NULL /*pSecAttrs*/,  PAGE_READONLY,
+                                                     0 /*cbMaxLow*/, 0 /*cbMaxHigh*/, NULL /*pwszName*/);
+                if (hMapping != NULL)
                 {
-                    DWORD cbActually = 0;
-                    if (   ReadFile(hFile, pbCache, cbCache, &cbActually, NULL)
-                        && cbActually == cbCache)
+                    KU8 *pbCache = (KU8 *)MapViewOfFile(hMapping, FILE_MAP_READ, 0 /*offFileHigh*/, 0 /*offFileLow*/, cbCache);
+                    if (pbCache)
                     {
-                        LARGE_INTEGER offZero;
-                        offZero.QuadPart = 0;
-                        if (SetFilePointerEx(hFile, offZero, NULL /*poffNew*/, FILE_BEGIN))
+                        /*
+                         * Create the cached file object.
+                         */
+                        PKFSWCACHEDFILE pCachedFile;
+                        KU32            cbPath = pFsObj->cchParent + pFsObj->cchName + 2;
+                        pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE,
+                                                                              sizeof(*pCachedFile) + cbPath);
+                        if (pCachedFile)
                         {
-                            /*
-                             * Create the cached file object.
-                             */
-                            PKFSWCACHEDFILE pCachedFile;
-                            KU32            cbPath = pFsObj->cchParent + pFsObj->cchName + 2;
-                            pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE,
-                                                                                  sizeof(*pCachedFile) + cbPath);
-                            if (pCachedFile)
-                            {
-                                pCachedFile->hCached  = hFile;
-                                pCachedFile->cbCached = cbCache;
-                                pCachedFile->pbCached = pbCache;
-                                pCachedFile->pFsObj   = pFsObj;
-                                kFsCacheObjGetFullPathA(pFsObj, pCachedFile->szPath, cbPath, '/');
-                                kFsCacheObjRetain(pFsObj);
-                                return pCachedFile;
-                            }
-
-                            KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n"));
+                            pCachedFile->hCached  = hFile;
+                            pCachedFile->hSection = hMapping;
+                            pCachedFile->cbCached = cbCache;
+                            pCachedFile->pbCached = pbCache;
+                            pCachedFile->pFsObj   = pFsObj;
+                            kFsCacheObjGetFullPathA(pFsObj, pCachedFile->szPath, cbPath, '/');
+                            kFsCacheObjRetain(pFsObj);
+
+                            g_cReadCachedFiles++;
+                            g_cbReadCachedFiles += cbCache;
+
+                            KWFS_LOG(("Cached '%s': %p LB %#x, hCached=%p\n", pCachedFile->szPath, pbCache, cbCache, hFile));
+                            return pCachedFile;
                         }
-                        else
-                            KWFS_LOG(("Failed to seek to start of cached file! err=%u\n", GetLastError()));
+
+                        KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n"));
                     }
                     else
-                        KWFS_LOG(("Failed to read %#x bytes into cache! err=%u cbActually=%#x\n",
-                                  cbCache, GetLastError(), cbActually));
-                    kHlpFree(pbCache);
+                        KWFS_LOG(("Failed to cache file: MapViewOfFile failed: %u\n", GetLastError()));
+                    CloseHandle(hMapping);
                 }
                 else
-                    KWFS_LOG(("Failed to allocate %#x bytes for cache!\n", cbCache));
+                    KWFS_LOG(("Failed to cache file: CreateFileMappingW failed: %u\n", GetLastError()));
             }
             else
                 KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart));
@@ -4635,12 +5404,52 @@ static PKFSWCACHEDFILE kwFsObjCacheNewFile(PKFSOBJ pFsObj)
 
 
 /**
+ * Kernel32 - Common code for kwFsObjCacheCreateFile and CreateFileMappingW/A.
+ */
+static KBOOL kwFsObjCacheCreateFileHandle(PKFSWCACHEDFILE pCachedFile, DWORD dwDesiredAccess, BOOL fInheritHandle,
+                                          KBOOL fIsFileHandle, HANDLE *phFile)
+{
+    HANDLE hProcSelf = GetCurrentProcess();
+    if (DuplicateHandle(hProcSelf, fIsFileHandle ? pCachedFile->hCached : pCachedFile->hSection,
+                        hProcSelf, phFile,
+                        dwDesiredAccess, fInheritHandle,
+                        0 /*dwOptions*/))
+    {
+        /*
+         * Create handle table entry for the duplicate handle.
+         */
+        PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
+        if (pHandle)
+        {
+            pHandle->enmType            = fIsFileHandle ? KWHANDLETYPE_FSOBJ_READ_CACHE : KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING;
+            pHandle->cRefs              = 1;
+            pHandle->offFile            = 0;
+            pHandle->hHandle            = *phFile;
+            pHandle->dwDesiredAccess    = dwDesiredAccess;
+            pHandle->u.pCachedFile      = pCachedFile;
+            if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, pHandle->hHandle))
+                return K_TRUE;
+
+            kHlpFree(pHandle);
+        }
+        else
+            KWFS_LOG(("Out of memory for handle!\n"));
+
+        CloseHandle(*phFile);
+        *phFile = INVALID_HANDLE_VALUE;
+    }
+    else
+        KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError()));
+    return K_FALSE;
+}
+
+
+/**
  * Kernel32 - Common code for CreateFileW and CreateFileA.
  */
 static KBOOL kwFsObjCacheCreateFile(PKFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL fInheritHandle, HANDLE *phFile)
 {
     *phFile = INVALID_HANDLE_VALUE;
-    kHlpAssert(pFsObj->fHaveStats);
 
     /*
      * At the moment we only handle existing files.
@@ -4648,39 +5457,12 @@ static KBOOL kwFsObjCacheCreateFile(PKFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL
     if (pFsObj->bObjType == KFSOBJ_TYPE_FILE)
     {
         PKFSWCACHEDFILE pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjGetUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE);
+        kHlpAssert(pFsObj->fHaveStats);
         if (   pCachedFile != NULL
             || (pCachedFile = kwFsObjCacheNewFile(pFsObj)) != NULL)
         {
-            HANDLE hProcSelf = GetCurrentProcess();
-            if (DuplicateHandle(hProcSelf, pCachedFile->hCached,
-                                hProcSelf, phFile,
-                                dwDesiredAccess, fInheritHandle,
-                                0 /*dwOptions*/))
-            {
-                /*
-                 * Create handle table entry for the duplicate handle.
-                 */
-                PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
-                if (pHandle)
-                {
-                    pHandle->enmType            = KWHANDLETYPE_FSOBJ_READ_CACHE;
-                    pHandle->offFile            = 0;
-                    pHandle->hHandle            = *phFile;
-                    pHandle->dwDesiredAccess    = dwDesiredAccess;
-                    pHandle->u.pCachedFile      = pCachedFile;
-                    if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
-                        return K_TRUE;
-
-                    kHlpFree(pHandle);
-                }
-                else
-                    KWFS_LOG(("Out of memory for handle!\n"));
-
-                CloseHandle(*phFile);
-                *phFile = INVALID_HANDLE_VALUE;
-            }
-            else
-                KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError()));
+            if (kwFsObjCacheCreateFileHandle(pCachedFile, dwDesiredAccess, fInheritHandle, K_TRUE /*fIsFileHandle*/, phFile))
+                return K_TRUE;
         }
     }
     /** @todo Deal with non-existing files if it becomes necessary (it's not for VS2010). */
@@ -4696,6 +5478,10 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dw
                                                     DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
 {
     HANDLE hFile;
+
+    /*
+     * Check for include files and similar that we do read-only caching of.
+     */
     if (dwCreationDisposition == FILE_OPEN_IF)
     {
         if (   dwDesiredAccess == GENERIC_READ
@@ -4708,7 +5494,7 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dw
                         && pSecAttrs->lpSecurityDescriptor == NULL ) )
                 {
                     const char *pszExt = kHlpGetExt(pszFilename);
-                    if (kwFsIsCachableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
+                    if (kwFsIsCacheableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
                     {
                         KFSLOOKUPERROR enmError;
                         PKFSOBJ pFsObj;
@@ -4752,8 +5538,16 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dw
         }
     }
 
+    /*
+     * Okay, normal.
+     */
     hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
                         dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        kHlpAssert(   KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles
+                   || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL);
+    }
     KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile));
     return hFile;
 }
@@ -4767,7 +5561,9 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD
     HANDLE hFile;
 
 #ifdef WITH_TEMP_MEMORY_FILES
-    /* First check for temporary files (cl.exe only). */
+    /*
+     * Check for temporary files (cl.exe only).
+     */
     if (   g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
         && !(dwFlagsAndAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_FLAG_BACKUP_SEMANTICS))
         && !(dwDesiredAccess & (GENERIC_EXECUTE | FILE_EXECUTE))
@@ -4779,7 +5575,9 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD
     }
 #endif
 
-    /* Then check for include files and similar. */
+    /*
+     * Check for include files and similar that we do read-only caching of.
+     */
     if (dwCreationDisposition == FILE_OPEN_IF)
     {
         if (   dwDesiredAccess == GENERIC_READ
@@ -4791,14 +5589,44 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD
                     || (   pSecAttrs->nLength == sizeof(*pSecAttrs)
                         && pSecAttrs->lpSecurityDescriptor == NULL ) )
                 {
-                    if (kwFsIsCachablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
+                    if (kwFsIsCacheablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
                     {
-                        /** @todo rewrite in pure UTF-16. */
-                        char szTmp[2048];
-                        KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
-                        if (cch < sizeof(szTmp))
-                            return kwSandbox_Kernel32_CreateFileA(szTmp, dwDesiredAccess, dwShareMode, pSecAttrs,
-                                                                  dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+                        KFSLOOKUPERROR enmError;
+                        PKFSOBJ pFsObj;
+                        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+                        pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError);
+                        if (pFsObj)
+                        {
+                            KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle,
+                                                               &hFile);
+                            kFsCacheObjRelease(g_pFsCache, pFsObj);
+                            if (fRc)
+                            {
+                                KWFS_LOG(("CreateFileW(%ls) -> %p [cached]\n", pwszFilename, hFile));
+                                return hFile;
+                            }
+                        }
+                        /* These are for nasm and yasm style header searching.  Cache will
+                           already have checked the directories for the file, no need to call
+                           CreateFile to do it again. */
+                        else if (enmError == KFSLOOKUPERROR_NOT_FOUND)
+                        {
+                            KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_FILE_NOT_FOUND\n", pwszFilename));
+                            return INVALID_HANDLE_VALUE;
+                        }
+                        else if (   enmError == KFSLOOKUPERROR_PATH_COMP_NOT_FOUND
+                                 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR)
+                        {
+                            KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_PATH_NOT_FOUND\n", pwszFilename));
+                            return INVALID_HANDLE_VALUE;
+                        }
+
+                        /* fallback */
+                        hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
+                                            dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+                        KWFS_LOG(("CreateFileW(%ls) -> %p (err=%u) [fallback]\n", pwszFilename, hFile, GetLastError()));
+                        return hFile;
                     }
                 }
                 else
@@ -4813,8 +5641,17 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD
     }
     else
         KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition));
+
+    /*
+     * Okay, normal.
+     */
     hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
                         dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        kHlpAssert(   KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles
+                   || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL);
+    }
     KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile));
     return hFile;
 }
@@ -4841,8 +5678,9 @@ static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove,
                 case KWHANDLETYPE_TEMP_FILE:
                     cbFile = pHandle->u.pTempFile->cbFile;
                     break;
-                case KWHANDLETYPE_TEMP_FILE_MAPPING:
 #endif
+                case KWHANDLETYPE_TEMP_FILE_MAPPING:
+                case KWHANDLETYPE_OUTPUT_BUF:
                 default:
                     kHlpAssertFailed();
                     SetLastError(ERROR_INVALID_FUNCTION);
@@ -4890,12 +5728,13 @@ static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove,
             }
             if (pcbMoveHi)
                 *pcbMoveHi = (KU64)offMove >> 32;
-            KWFS_LOG(("SetFilePointer(%p) -> %#llx [cached]\n", hFile, offMove));
+            KWFS_LOG(("SetFilePointer(%p,%#x,?,%u) -> %#llx [%s]\n", hFile, cbMove, dwMoveMethod, offMove,
+                      pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp"));
             SetLastError(NO_ERROR);
             return (KU32)offMove;
         }
     }
-    KWFS_LOG(("SetFilePointer(%p)\n", hFile));
+    KWFS_LOG(("SetFilePointer(%p, %d, %p=%d, %d)\n", hFile, cbMove, pcbMoveHi ? *pcbMoveHi : 0, dwMoveMethod));
     return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod);
 }
 
@@ -4922,8 +5761,9 @@ static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEG
                 case KWHANDLETYPE_TEMP_FILE:
                     cbFile = pHandle->u.pTempFile->cbFile;
                     break;
-                case KWHANDLETYPE_TEMP_FILE_MAPPING:
 #endif
+                case KWHANDLETYPE_TEMP_FILE_MAPPING:
+                case KWHANDLETYPE_OUTPUT_BUF:
                 default:
                     kHlpAssertFailed();
                     SetLastError(ERROR_INVALID_FUNCTION);
@@ -4971,7 +5811,8 @@ static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEG
             }
             if (poffNew)
                 poffNew->QuadPart = offMyMove;
-            KWFS_LOG(("SetFilePointerEx(%p) -> TRUE, %#llx [cached]\n", hFile, offMyMove));
+            KWFS_LOG(("SetFilePointerEx(%p,%#llx,,%u) -> TRUE, %#llx [%s]\n", hFile, offMove.QuadPart, dwMoveMethod, offMyMove,
+                      pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp"));
             return TRUE;
         }
     }
@@ -4984,7 +5825,9 @@ static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEG
 static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPDWORD pcbActuallyRead,
                                                LPOVERLAPPED pOverlapped)
 {
+    BOOL        fRet;
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    g_cReadFileCalls++;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
@@ -4999,8 +5842,6 @@ static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DW
                     KU32            cbActually = pCachedFile->cbCached - pHandle->offFile;
                     if (cbActually > cbToRead)
                         cbActually = cbToRead;
-                    else if (cbActually < cbToRead)                                            // debug debug debug
-                        kHlpMemSet((KU8 *)pvBuffer + cbActually, '\0', cbToRead - cbActually); // debug debug debug
 
 #ifdef WITH_HASH_MD5_CACHE
                     if (g_Sandbox.pHashHead)
@@ -5018,6 +5859,10 @@ static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DW
                     kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
                     *pcbActuallyRead = cbActually;
 
+                    g_cbReadFileFromReadCached += cbActually;
+                    g_cbReadFileTotal          += cbActually;
+                    g_cReadFileFromReadCached++;
+
                     KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually));
                     return TRUE;
                 }
@@ -5076,12 +5921,17 @@ static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DW
                     kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
                     *pcbActuallyRead = cbActually;
 
+                    g_cbReadFileTotal         += cbActually;
+                    g_cbReadFileFromInMemTemp += cbActually;
+                    g_cReadFileFromInMemTemp++;
+
                     KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually));
                     return TRUE;
                 }
+#endif /* WITH_TEMP_MEMORY_FILES */
 
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
-#endif /* WITH_TEMP_MEMORY_FILES */
+                case KWHANDLETYPE_OUTPUT_BUF:
                 default:
                     kHlpAssertFailed();
                     SetLastError(ERROR_INVALID_FUNCTION);
@@ -5091,8 +5941,11 @@ static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DW
         }
     }
 
-    KWFS_LOG(("ReadFile(%p)\n", hFile));
-    return ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
+    fRet = ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
+    if (fRet && pcbActuallyRead)
+        g_cbReadFileTotal += *pcbActuallyRead;
+    KWFS_LOG(("ReadFile(%p,%p,%#x,,) -> %d, %#x\n", hFile, pvBuffer, cbToRead, fRet, pcbActuallyRead ? *pcbActuallyRead : 0));
+    return fRet;
 }
 
 
@@ -5115,8 +5968,139 @@ static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer,
     return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine);
 }
 
-#ifdef WITH_TEMP_MEMORY_FILES
+#ifdef WITH_STD_OUT_ERR_BUFFERING
+
+/**
+ * Write something to a handle, making sure everything is actually written.
+ *
+ * @param   hHandle         Where to write it to.
+ * @param   pchBuf          What to write
+ * @param   cchToWrite      How much to write.
+ */
+static void kwSandboxOutBufWriteIt(HANDLE hFile, char const *pchBuf, KU32 cchToWrite)
+{
+    if (cchToWrite > 0)
+    {
+        DWORD cchWritten = 0;
+        if (WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL))
+        {
+            if (cchWritten == cchToWrite)
+            { /* likely */ }
+            else
+            {
+                do
+                {
+                    pchBuf += cchWritten;
+                    cchToWrite -= cchWritten;
+                    cchWritten = 0;
+                } while (   cchToWrite > 0
+                         && WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL));
+            }
+        }
+        else
+            kHlpAssertFailed();
+    }
+}
+
+
+/**
+ * Worker for WriteFile when the output isn't going to the console.
+ *
+ * @param   pSandbox            The sandbox.
+ * @param   pOutBuf             The output buffer.
+ * @param   pchBuffer           What to write.
+ * @param   cchToWrite          How much to write.
+ */
+static void kwSandboxOutBufWrite(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pOutBuf, const char *pchBuffer, KU32 cchToWrite)
+{
+    if (pOutBuf->u.Fully.cchBufAlloc > 0)
+    { /* likely */ }
+    else
+    {
+        /* No realloc, max size is 64KB. */
+        pOutBuf->u.Fully.cchBufAlloc = 0x10000;
+        pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc);
+        if (!pOutBuf->u.Fully.pchBuf)
+        {
+            while (   !pOutBuf->u.Fully.pchBuf
+                   && pOutBuf->u.Fully.cchBufAlloc > 64)
+            {
+                pOutBuf->u.Fully.cchBufAlloc /= 2;
+                pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc);
+            }
+            if (!pOutBuf->u.Fully.pchBuf)
+            {
+                pOutBuf->u.Fully.cchBufAlloc = sizeof(pOutBuf->abPadding);
+                pOutBuf->u.Fully.pchBuf      = pOutBuf->abPadding;
+            }
+        }
+    }
+
+    /*
+     * Special case: Output ends with newline and fits in the buffer.
+     */
+    if (   cchToWrite > 1
+        && pchBuffer[cchToWrite - 1] == '\n'
+        && cchToWrite <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf)
+    {
+        kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchToWrite);
+        pOutBuf->u.Fully.cchBuf += cchToWrite;
+    }
+    else
+    {
+        /*
+         * Work thru the text line by line, flushing the buffer when
+         * appropriate.  The buffer is not a line buffer here, it's a
+         * full buffer.
+         */
+        while (cchToWrite > 0)
+        {
+            char const *pchNewLine = (const char *)memchr(pchBuffer, '\n', cchToWrite);
+            KU32        cchLine    = pchNewLine ? (KU32)(pchNewLine - pchBuffer) + 1 : cchToWrite;
+            if (cchLine <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf)
+            {
+                kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchLine);
+                pOutBuf->u.Fully.cchBuf += cchLine;
+            }
+            /*
+             * Option one: Flush the buffer and the current line.
+             *
+             * We choose this one when the line won't ever fit, or when we have
+             * an incomplete line in the buffer.
+             */
+            else if (   cchLine >= pOutBuf->u.Fully.cchBufAlloc
+                     || pOutBuf->u.Fully.cchBuf == 0
+                     || pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf - 1] != '\n')
+            {
+                KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes, writing %u bytes\n", pOutBuf->u.Fully.cchBuf, cchLine));
+                if (pOutBuf->u.Fully.cchBuf > 0)
+                {
+                    kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf);
+                    pOutBuf->u.Fully.cchBuf = 0;
+                }
+                kwSandboxOutBufWriteIt(pOutBuf->hBackup, pchBuffer, cchLine);
+            }
+            /*
+             * Option two: Only flush the lines in the buffer.
+             */
+            else
+            {
+                KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes\n", pOutBuf->u.Fully.cchBuf));
+                kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf);
+                kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[0], pchBuffer, cchLine);
+                pOutBuf->u.Fully.cchBuf = cchLine;
+            }
 
+            /* advance */
+            pchBuffer  += cchLine;
+            cchToWrite -= cchLine;
+        }
+    }
+}
+
+#endif  /* WITH_STD_OUT_ERR_BUFFERING */
+
+#ifdef WITH_TEMP_MEMORY_FILES
 static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded)
 {
     KU32 cbMinFile = offFile + cbNeeded;
@@ -5171,14 +6155,18 @@ static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32
     kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded));
     return K_FALSE;
 }
+#endif /* WITH_TEMP_MEMORY_FILES */
 
 
+#if defined(WITH_TEMP_MEMORY_FILES) || defined(WITH_STD_OUT_ERR_BUFFERING)
 /** Kernel32 - WriteFile */
 static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten,
                                                 LPOVERLAPPED pOverlapped)
 {
+    BOOL        fRet;
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
-    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+    g_cWriteFileCalls++;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_fCtrlC);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5186,6 +6174,7 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer,
         {
             switch (pHandle->enmType)
             {
+# ifdef WITH_TEMP_MEMORY_FILES
                 case KWHANDLETYPE_TEMP_FILE:
                 {
                     PKWFSTEMPFILE   pTempFile  = pHandle->u.pTempFile;
@@ -5231,6 +6220,11 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer,
                             pTempFile->cbFile = pHandle->offFile;
 
                         *pcbActuallyWritten = cbToWrite;
+
+                        g_cbWriteFileTotal += cbToWrite;
+                        g_cbWriteFileToInMemTemp += cbToWrite;
+                        g_cWriteFileToInMemTemp++;
+
                         KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite));
                         return TRUE;
                     }
@@ -5240,6 +6234,7 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer,
                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                     return FALSE;
                 }
+# endif
 
                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
                     kHlpAssertFailed();
@@ -5247,6 +6242,35 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer,
                     *pcbActuallyWritten = 0;
                     return FALSE;
 
+# if defined(WITH_STD_OUT_ERR_BUFFERING) || defined(WITH_CONSOLE_OUTPUT_BUFFERING)
+                /*
+                 * Standard output & error.
+                 */
+                case KWHANDLETYPE_OUTPUT_BUF:
+                {
+                    PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf;
+                    if (pOutBuf->fIsConsole)
+                    {
+                        kwSandboxConsoleWriteA(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite);
+                        KWOUT_LOG(("WriteFile(%p [console]) -> TRUE\n", hFile));
+                    }
+                    else
+                    {
+#  ifdef WITH_STD_OUT_ERR_BUFFERING
+                        kwSandboxOutBufWrite(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite);
+                        KWOUT_LOG(("WriteFile(%p [std%s], 's*.*', %#x) -> TRUE\n", hFile,
+                                   pOutBuf == &g_Sandbox.StdErr ? "err" : "out", cbToWrite, cbToWrite, pvBuffer, cbToWrite));
+#  else
+                        kHlpAssertFailed();
+#  endif
+                    }
+                    if (pcbActuallyWritten)
+                        *pcbActuallyWritten = cbToWrite;
+                    g_cbWriteFileTotal += cbToWrite;
+                    return TRUE;
+                }
+# endif
+
                 default:
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
                     kHlpAssertFailed();
@@ -5257,25 +6281,11 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer,
         }
     }
 
-#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
-    /*
-     * Check for stdout and stderr.
-     */
-    if (   g_Sandbox.StdErr.hOutput == hFile
-        || g_Sandbox.StdOut.hOutput == hFile)
-    {
-        PKWCONSOLEOUTPUTLINE pLineBuf = g_Sandbox.StdErr.hOutput == hFile ? &g_Sandbox.StdErr : &g_Sandbox.StdOut;
-        if (pLineBuf->fIsConsole)
-        {
-            kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (const char *)pvBuffer, cbToWrite);
-            KWFS_LOG(("WriteFile(console) -> TRUE\n", hFile));
-            return TRUE;
-        }
-    }
-#endif
-
-    KWFS_LOG(("WriteFile(%p)\n", hFile));
-    return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
+    fRet = WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
+    if (fRet && pcbActuallyWritten)
+        g_cbWriteFileTotal += *pcbActuallyWritten;
+    KWFS_LOG(("WriteFile(%p,,%#x) -> %d, %#x\n", hFile, cbToWrite, fRet, pcbActuallyWritten ? *pcbActuallyWritten : 0));
+    return fRet;
 }
 
 
@@ -5298,6 +6308,9 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer
     return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine);
 }
 
+#endif /* WITH_TEMP_MEMORY_FILES || WITH_STD_OUT_ERR_BUFFERING */
+
+#ifdef WITH_TEMP_MEMORY_FILES
 
 /** Kernel32 - SetEndOfFile; */
 static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
@@ -5332,6 +6345,11 @@ static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
                     SetLastError(ERROR_ACCESS_DENIED);
                     return FALSE;
 
+                case KWHANDLETYPE_OUTPUT_BUF:
+                    kHlpAssertFailed();
+                    SetLastError(pHandle->u.pOutBuf->fIsConsole ? ERROR_INVALID_OPERATION : ERROR_ACCESS_DENIED);
+                    return FALSE;
+
                 default:
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
                     kHlpAssertFailed();
@@ -5365,6 +6383,24 @@ static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile)
                 case KWHANDLETYPE_TEMP_FILE:
                     KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile));
                     return FILE_TYPE_DISK;
+
+                case KWHANDLETYPE_OUTPUT_BUF:
+                {
+                    PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf;
+                    DWORD fRet;
+                    if (pOutBuf->fFileType != KU8_MAX)
+                    {
+                        fRet = (pOutBuf->fFileType & 0xf) | ((pOutBuf->fFileType & (FILE_TYPE_REMOTE >> 8)) << 8);
+                        KWFS_LOG(("GetFileType(%p) -> %#x [outbuf]\n", hFile, fRet));
+                    }
+                    else
+                    {
+                        fRet = GetFileType(hFile);
+                        KWFS_LOG(("GetFileType(%p) -> %#x [outbuf, fallback]\n", hFile, fRet));
+                    }
+                    return fRet;
+                }
+
             }
         }
     }
@@ -5397,6 +6433,10 @@ static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHigh
                     KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
                     return pHandle->u.pTempFile->cbFile;
 
+                case KWHANDLETYPE_OUTPUT_BUF:
+                    /* do default */
+                    break;
+
                 default:
                     kHlpAssertFailed();
                     SetLastError(ERROR_INVALID_FUNCTION);
@@ -5432,6 +6472,10 @@ static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER
                     pcbFile->QuadPart = pHandle->u.pTempFile->cbFile;
                     return TRUE;
 
+                case KWHANDLETYPE_OUTPUT_BUF:
+                    /* do default */
+                    break;
+
                 default:
                     kHlpAssertFailed();
                     SetLastError(ERROR_INVALID_FUNCTION);
@@ -5445,11 +6489,12 @@ static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER
 }
 
 
-/** Kernel32 - CreateFileMapping  */
+/** Kernel32 - CreateFileMappingW  */
 static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs,
                                                            DWORD fProtect, DWORD dwMaximumSizeHigh,
                                                            DWORD dwMaximumSizeLow, LPCWSTR pwszName)
 {
+    HANDLE      hMapping;
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
@@ -5469,7 +6514,7 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECUR
                              || dwMaximumSizeLow == pTempFile->cbFile)
                         && pwszName == NULL)
                     {
-                        HANDLE hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
+                        hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
                         KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping));
                         return hMapping;
                     }
@@ -5478,18 +6523,55 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECUR
                     SetLastError(ERROR_ACCESS_DENIED);
                     return INVALID_HANDLE_VALUE;
                 }
+
+                /* moc.exe benefits from this. */
+                case KWHANDLETYPE_FSOBJ_READ_CACHE:
+                {
+                    PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile;
+                    if (   (   fProtect == PAGE_READONLY
+                            || fProtect == PAGE_EXECUTE_READ)
+                        && dwMaximumSizeHigh == 0
+                        &&  (   dwMaximumSizeLow == 0
+                             || dwMaximumSizeLow == pCachedFile->cbCached)
+                        && pwszName == NULL)
+                    {
+                        if (kwFsObjCacheCreateFileHandle(pCachedFile, GENERIC_READ, FALSE /*fInheritHandle*/,
+                                                         K_FALSE /*fIsFileHandle*/, &hMapping))
+                        { /* likely */ }
+                        else
+                            hMapping = NULL;
+                        KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [cached]\n", hFile, fProtect, hMapping));
+                        return hMapping;
+                    }
+
+                    /* Do fallback (for .pch). */
+                    kHlpAssertMsg(fProtect == PAGE_WRITECOPY,
+                                  ("fProtect=%#x cb=%#x'%08x name=%p\n",
+                                   fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName));
+
+                    hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
+                    KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p [cached-fallback]\n",
+                              hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping));
+                    return hMapping;
+                }
+
+                /** @todo read cached memory mapped files too for moc.   */
             }
         }
     }
 
-    KWFS_LOG(("CreateFileMappingW(%p)\n", hFile));
-    return CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
+    hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
+    KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p\n",
+              hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping));
+    return hMapping;
 }
 
+
 /** Kernel32 - MapViewOfFile  */
-static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
-                                                      DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
+static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
+                                                     DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
 {
+    PVOID       pvRet;
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
@@ -5497,12 +6579,45 @@ static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwD
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
         if (pHandle != NULL)
         {
+            KU32 idxMapping;
+
+            /*
+             * Ensure one free entry in the mapping tracking table first,
+             * since this is common to both temporary and cached files.
+             */
+            if (g_Sandbox.cMemMappings + 1 <= g_Sandbox.cMemMappingsAlloc)
+            { /* likely */ }
+            else
+            {
+                void *pvNew;
+                KU32 cNew = g_Sandbox.cMemMappingsAlloc;
+                if (cNew)
+                    cNew *= 2;
+                else
+                    cNew = 32;
+                pvNew = kHlpRealloc(g_Sandbox.paMemMappings, cNew * sizeof(g_Sandbox.paMemMappings));
+                if (pvNew)
+                    g_Sandbox.paMemMappings = (PKWMEMMAPPING)pvNew;
+                else
+                {
+                    kwErrPrintf("Failed to grow paMemMappings from %#x to %#x!\n", g_Sandbox.cMemMappingsAlloc, cNew);
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    return NULL;
+                }
+                g_Sandbox.cMemMappingsAlloc = cNew;
+            }
+
+            /*
+             * Type specific work.
+             */
             switch (pHandle->enmType)
             {
                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
                 case KWHANDLETYPE_TEMP_FILE:
+                case KWHANDLETYPE_OUTPUT_BUF:
+                default:
                     kHlpAssertFailed();
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    SetLastError(ERROR_INVALID_OPERATION);
                     return NULL;
 
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
@@ -5553,8 +6668,9 @@ static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwD
                         pTempFile->cMappings++;
                         kHlpAssert(pTempFile->cMappings == 1);
 
-                        KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pTempFile->paSegs[0].pbData));
-                        return pTempFile->paSegs[0].pbData;
+                        pvRet = pTempFile->paSegs[0].pbData;
+                        KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pvRet));
+                        break;
                     }
 
                     kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
@@ -5562,33 +6678,136 @@ static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwD
                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                     return NULL;
                 }
+
+                /*
+                 * This is simple in comparison to the above temporary file code.
+                 */
+                case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING:
+                {
+                    PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile;
+                    if (   dwDesiredAccess == FILE_MAP_READ
+                        && offFileHigh == 0
+                        && offFileLow  == 0
+                        && (cbToMap == 0 || cbToMap == pCachedFile->cbCached) )
+                    {
+                        pvRet = pCachedFile->pbCached;
+                        KWFS_LOG(("CreateFileMappingW(%p) -> %p [cached]\n", hSection, pvRet));
+                        break;
+                    }
+                    kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
+                                         dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pCachedFile->cbCached));
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    return NULL;
+                }
             }
+
+            /*
+             * Insert into the mapping tracking table.  This is common
+             * and we should only get here with a non-NULL pvRet.
+             *
+             * Note! We could look for duplicates and do ref counting, but it's
+             *       easier to just append for now.
+             */
+            kHlpAssert(pvRet != NULL);
+            idxMapping = g_Sandbox.cMemMappings;
+            kHlpAssert(idxMapping < g_Sandbox.cMemMappingsAlloc);
+
+            g_Sandbox.paMemMappings[idxMapping].cRefs         = 1;
+            g_Sandbox.paMemMappings[idxMapping].pvMapping     = pvRet;
+            g_Sandbox.paMemMappings[idxMapping].enmType       = pHandle->enmType;
+            g_Sandbox.paMemMappings[idxMapping].u.pCachedFile = pHandle->u.pCachedFile;
+            g_Sandbox.cMemMappings++;
+
+            return pvRet;
         }
     }
 
-    KWFS_LOG(("MapViewOfFile(%p)\n", hSection));
-    return MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
+    pvRet = MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
+    KWFS_LOG(("MapViewOfFile(%p, %#x, %#x, %#x, %#x) -> %p\n",
+              hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvRet));
+    return pvRet;
 }
-/** @todo MapViewOfFileEx */
 
 
+/** Kernel32 - MapViewOfFileEx  */
+static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFileEx(HANDLE hSection, DWORD dwDesiredAccess,
+                                                       DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap, PVOID pvMapAddr)
+{
+    PVOID       pvRet;
+    KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+    if (idxHandle < g_Sandbox.cHandles)
+    {
+        PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
+        if (pHandle != NULL)
+        {
+            switch (pHandle->enmType)
+            {
+                case KWHANDLETYPE_TEMP_FILE_MAPPING:
+                    KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - temporary file!\n",
+                              hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr));
+                    if (!pvMapAddr)
+                        return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
+                    kHlpAssertFailed();
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    return NULL;
+
+                case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING:
+                    KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - read cached file!\n",
+                              hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr));
+                    if (!pvMapAddr)
+                        return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
+                    /* We can use fallback here as the handle is an actual section handle. */
+                    break;
+
+                case KWHANDLETYPE_FSOBJ_READ_CACHE:
+                case KWHANDLETYPE_TEMP_FILE:
+                case KWHANDLETYPE_OUTPUT_BUF:
+                default:
+                    kHlpAssertFailed();
+                    SetLastError(ERROR_INVALID_OPERATION);
+                    return NULL;
+            }
+        }
+    }
+
+    pvRet = MapViewOfFileEx(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr);
+    KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) -> %p\n",
+              hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr, pvRet));
+    return pvRet;
+
+}
+
 /** Kernel32 - UnmapViewOfFile  */
 static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
 {
-    /* Is this one of our temporary mappings? */
-    PKWFSTEMPFILE pCur = g_Sandbox.pTempFileHead;
+    /*
+     * Consult the memory mapping tracker.
+     */
+    PKWMEMMAPPING   paMemMappings = g_Sandbox.paMemMappings;
+    KU32            idxMapping    = g_Sandbox.cMemMappings;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
-    while (pCur)
-    {
-        if (   pCur->cMappings > 0
-            && pCur->paSegs[0].pbData == (KU8 *)pvBase)
+    while (idxMapping-- > 0)
+        if (paMemMappings[idxMapping].pvMapping == pvBase)
         {
-            pCur->cMappings--;
-            KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
+            /* Type specific stuff. */
+            if (paMemMappings[idxMapping].enmType == KWHANDLETYPE_TEMP_FILE_MAPPING)
+            {
+                KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
+                paMemMappings[idxMapping].u.pTempFile->cMappings--;
+            }
+            else
+                KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [cached]\n", pvBase));
+
+            /* Deref and probably free it. */
+            if (--paMemMappings[idxMapping].cRefs == 0)
+            {
+                g_Sandbox.cMemMappings--;
+                if (idxMapping != g_Sandbox.cMemMappings)
+                    paMemMappings[idxMapping] = paMemMappings[g_Sandbox.cMemMappings];
+            }
             return TRUE;
         }
-        pCur = pCur->pNext;
-    }
 
     KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase));
     return UnmapViewOfFile(pvBase);
@@ -5596,42 +6815,115 @@ static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
 
 /** @todo UnmapViewOfFileEx */
 
-
 #endif /* WITH_TEMP_MEMORY_FILES */
 
+
+/** Kernel32 - DuplicateHandle */
+static BOOL WINAPI kwSandbox_Kernel32_DuplicateHandle(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, PHANDLE phNew,
+                                                      DWORD dwDesiredAccess, BOOL fInheritHandle, DWORD dwOptions)
+{
+    BOOL fRet;
+
+    /*
+     * We must catch our handles being duplicated.
+     */
+    if (hSrcProc == GetCurrentProcess())
+    {
+        KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSrc);
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+        if (idxHandle < g_Sandbox.cHandles)
+        {
+            PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
+            if (pHandle)
+            {
+                fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions);
+                if (fRet)
+                {
+                    if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, *phNew))
+                    {
+                        pHandle->cRefs++;
+                        KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> TRUE, %p [intercepted handle] enmType=%d cRef=%d\n",
+                                  hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew,
+                                  pHandle->enmType, pHandle->cRefs));
+                    }
+                    else
+                    {
+                        fRet = FALSE;
+                        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                        KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> !FALSE!, %p [intercepted handle] enmType=%d\n",
+                                  hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew, pHandle->enmType));
+                    }
+                }
+                else
+                    KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> FALSE [intercepted handle] enmType=%d\n",
+                              hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, pHandle->enmType));
+                return fRet;
+            }
+        }
+    }
+
+    /*
+     * Not one of ours, just do what the caller asks and log it.
+     */
+    fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions);
+    KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> %d, %p\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess,
+              fInheritHandle, dwOptions, fRet, *phNew));
+    return fRet;
+}
+
+
 /** Kernel32 - CloseHandle */
 static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject)
 {
     BOOL        fRet;
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
-    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
-    if (   idxHandle < g_Sandbox.cHandles
-        && g_Sandbox.papHandles[idxHandle] != NULL)
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_fCtrlC);
+    if (idxHandle < g_Sandbox.cHandles)
     {
-        fRet = CloseHandle(hObject);
-        if (fRet)
+        PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
+        if (pHandle)
         {
-            PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
-            g_Sandbox.papHandles[idxHandle] = NULL;
-            g_Sandbox.cActiveHandles--;
+            /* Prevent the closing of the standard output and error handles. */
+            if (   pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF
+                || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle))
+            {
+                fRet = CloseHandle(hObject);
+                if (fRet)
+                {
+                    PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
+                    g_Sandbox.papHandles[idxHandle] = NULL;
+                    g_Sandbox.cActiveHandles--;
+                    kHlpAssert(g_Sandbox.cActiveHandles >= g_Sandbox.cFixedHandles);
+                    if (--pHandle->cRefs == 0)
+                    {
 #ifdef WITH_TEMP_MEMORY_FILES
-            if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
+                        if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
+                        {
+                            kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
+                            pHandle->u.pTempFile->cActiveHandles--;
+                        }
+#endif
+                        kHlpFree(pHandle);
+                        KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, freed]\n", hObject));
+                    }
+                    else
+                        KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, not freed]\n", hObject));
+                }
+                else
+                    KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
+            }
+            else
             {
-                kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
-                pHandle->u.pTempFile->cActiveHandles--;
+                KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle] Ignored closing of std%s!\n",
+                          hObject, hObject == g_Sandbox.StdErr.hOutput ? "err" : "out"));
+                fRet = TRUE;
             }
-#endif
-            kHlpFree(pHandle);
-            KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));
+            return fRet;
         }
-        else
-            KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
-    }
-    else
-    {
-        KWFS_LOG(("CloseHandle(%p)\n", hObject));
-        fRet = CloseHandle(hObject);
     }
+
+    fRet = CloseHandle(hObject);
+    KWFS_LOG(("CloseHandle(%p) -> %d\n", hObject, fRet));
     return fRet;
 }
 
@@ -5641,7 +6933,7 @@ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename)
 {
     DWORD       fRet;
     const char *pszExt = kHlpGetExt(pszFilename);
-    if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
+    if (kwFsIsCacheableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
     {
         KFSLOOKUPERROR enmError;
         PKFSOBJ pFsObj;
@@ -5674,7 +6966,7 @@ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename)
 static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
 {
     DWORD fRet;
-    if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
+    if (kwFsIsCacheablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
     {
         KFSLOOKUPERROR enmError;
         PKFSOBJ pFsObj;
@@ -5709,7 +7001,7 @@ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
 static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath)
 {
     DWORD cwcRet;
-    if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
+    if (kwFsIsCacheablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
     {
         KFSLOOKUPERROR enmError;
         PKFSOBJ pObj;
@@ -5814,9 +7106,8 @@ static void kwSandboxConsoleWriteIt(PKWSANDBOX pSandbox, wchar_t const *pwcBuf,
                 {
                     off += cwcWritten;
                     cwcWritten = 0;
-                }
-                while (   off < cwcToWrite
-                       && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL));
+                } while (   off < cwcToWrite
+                         && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL));
                 kHlpAssert(off == cwcWritten);
             }
         }
@@ -5836,6 +7127,7 @@ static void kwSandboxConsoleFlushCombined(PKWSANDBOX pSandbox)
 {
     if (pSandbox->Combined.cwcBuf > 0)
     {
+        KWOUT_LOG(("kwSandboxConsoleFlushCombined: %u wchars\n", pSandbox->Combined.cwcBuf));
         kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf);
         pSandbox->Combined.cwcBuf = 0;
     }
@@ -5862,7 +7154,7 @@ static void kwSandboxConsoleAddToCombined(PKWSANDBOX pSandbox, wchar_t const *pw
     }
     else
     {
-        memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t));
+        kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t));
         pSandbox->Combined.cwcBuf += cwcBuf;
     }
 }
@@ -5873,30 +7165,38 @@ static void kwSandboxConsoleAddToCombined(PKWSANDBOX pSandbox, wchar_t const *pw
  *
  * @param   pSandbox            The sandbox.
  * @param   pLineBuf            The line buffer.
+ * @param   pszName             The line buffer name (for logging)
  */
-static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf)
+static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pszName)
 {
-    if (pLineBuf->cwcBuf > 0)
+    if (pLineBuf->fIsConsole)
     {
-        if (pLineBuf->fIsConsole)
+        if (pLineBuf->u.Con.cwcBuf > 0)
         {
-            if (pLineBuf->cwcBuf < pLineBuf->cwcBufAlloc)
+            KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u wchars\n", pszName, pLineBuf->u.Con.cwcBuf));
+
+            if (pLineBuf->u.Con.cwcBuf < pLineBuf->u.Con.cwcBufAlloc)
             {
-                pLineBuf->pwcBuf[pLineBuf->cwcBuf++] = '\n';
-                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_FALSE /*fBrokenLine*/);
+                pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf++] = '\n';
+                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_FALSE /*fBrokenLine*/);
             }
             else
             {
-                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
+                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/);
                 kwSandboxConsoleAddToCombined(pSandbox, L"\n", 1, K_TRUE /*fBrokenLine*/);
             }
-            pLineBuf->cwcBuf = 0;
-        }
-        else
-        {
-            kHlpAssertFailed();
+            pLineBuf->u.Con.cwcBuf = 0;
         }
     }
+#ifdef WITH_STD_OUT_ERR_BUFFERING
+    else if (pLineBuf->u.Fully.cchBuf > 0)
+    {
+        KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u bytes\n", pszName, pLineBuf->u.Fully.cchBuf));
+
+        kwSandboxOutBufWriteIt(pLineBuf->hBackup, pLineBuf->u.Fully.pchBuf, pLineBuf->u.Fully.cchBuf);
+        pLineBuf->u.Fully.cchBuf = 0;
+    }
+#endif
 }
 
 
@@ -5909,41 +7209,92 @@ static void kwSandboxConsoleFlushAll(PKWSANDBOX pSandbox)
 {
     /*
      * First do the cl.exe source file supression trick, if applicable.
+     * The output ends up on CONOUT$ if either StdOut or StdErr is a console
+     * handle.
      */
-    if (   pSandbox->Combined.cwcBuf >= 3
-        && pSandbox->StdOut.cwcBuf == 0
-        && pSandbox->StdErr.cwcBuf == 0
-        && pSandbox->Combined.cFlushes == 0
-        && pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
+    if (   pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
+        && pSandbox->Combined.cFlushes == 0)
     {
-        KI32    off = pSandbox->Combined.cwcBuf - 1;
-        if (pSandbox->Combined.wszBuf[off] == '\n')
+        if (   pSandbox->StdOut.fIsConsole
+            || pSandbox->StdErr.fIsConsole)
         {
-            KBOOL fOk = K_TRUE;
-            while (off-- > 0)
+            if (   pSandbox->Combined.cwcBuf >= 3
+                && (pSandbox->StdOut.fIsConsole ? pSandbox->StdOut.u.Con.cwcBuf : pSandbox->StdOut.u.Fully.cchBuf) == 0
+                && (pSandbox->StdErr.fIsConsole ? pSandbox->StdErr.u.Con.cwcBuf : pSandbox->StdErr.u.Fully.cchBuf) == 0 )
             {
-                wchar_t const wc = pSandbox->Combined.wszBuf[off];
-                if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-')
-                { /* likely */ }
-                else
+                KI32    off = pSandbox->Combined.cwcBuf - 1;
+                if (pSandbox->Combined.wszBuf[off] == '\n')
                 {
-                    fOk = K_FALSE;
-                    break;
+                    KBOOL fOk = K_TRUE;
+                    while (off-- > 0)
+                    {
+                        wchar_t const wc = pSandbox->Combined.wszBuf[off];
+                        if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-')
+                        { /* likely */ }
+                        else
+                        {
+                            fOk = K_FALSE;
+                            break;
+                        }
+                    }
+                    if (fOk)
+                    {
+                        KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*ls in combined console buffer\n",
+                                   pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf));
+                        pSandbox->Combined.cwcBuf = 0;
+                        return;
+                    }
                 }
+                KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*ls in combined console buffer\n",
+                           pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf));
             }
-            if (fOk)
+        }
+#ifdef WITH_STD_OUT_ERR_BUFFERING
+        /*
+         * Otherwise, it goes to standard output (redirected).
+         */
+        else if (   pSandbox->StdErr.u.Fully.cchBuf == 0
+                 && pSandbox->StdOut.u.Fully.cchBuf >= 3)
+        {
+            char const *pchBuf = pSandbox->StdOut.u.Fully.pchBuf;
+            KI32        off    = pSandbox->StdOut.u.Fully.cchBuf - 1;
+            kHlpAssert(pSandbox->Combined.cFlushes == 0 && pSandbox->Combined.cwcBuf == 0); /* unused! */
+
+            if (pchBuf[off] == '\n')
             {
-                pSandbox->Combined.cwcBuf = 0;
-                return;
+                KBOOL fOk = K_TRUE;
+                if (pchBuf[off - 1] == '\r')
+                    off--;
+                while (off-- > 0)
+                {
+                    char const ch = pchBuf[off];
+                    if (isalnum(ch) || ch == '.' || ch == ' ' || ch == '_' || ch == '-')
+                    { /* likely */ }
+                    else
+                    {
+                        fOk = K_FALSE;
+                        break;
+                    }
+                }
+                if (fOk)
+                {
+                    KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*s in stdout buffer\n",
+                               pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf));
+                    pSandbox->StdOut.u.Fully.cchBuf = 0;
+                    return;
+                }
             }
+            KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*s in stdout buffer\n",
+                       pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf));
         }
+#endif
     }
 
     /*
      * Flush the two line buffer, the the combined buffer.
      */
-    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr);
-    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut);
+    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr, "StdErr");
+    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut, "StdOut");
     kwSandboxConsoleFlushCombined(pSandbox);
 }
 
@@ -5956,8 +7307,9 @@ static void kwSandboxConsoleFlushAll(PKWSANDBOX pSandbox)
  * @param   pwcBuffer           The buffer to write.
  * @param   cwcToWrite          The number of wchar_t's in the buffer.
  */
-static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
+static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
 {
+    kHlpAssert(pLineBuf->fIsConsole);
     if (cwcToWrite > 0)
     {
         /*
@@ -5975,34 +7327,37 @@ static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
         if (offLastIncompleteLine < cwcToWrite)
         {
             /* Need to grow the line buffer? */
-            KU32 cwcNeeded = offLastIncompleteLine != 0 ? offLastIncompleteLine : cchLastIncompleteLine + pLineBuf->cwcBuf;
-            if (cwcNeeded > pLineBuf->cwcBufAlloc)
+            KU32 cwcNeeded = offLastIncompleteLine == 0
+                           ? pLineBuf->u.Con.cwcBuf + cchLastIncompleteLine /* incomplete line, append to line buffer */
+                           : cchLastIncompleteLine; /* Only the final incomplete line (if any) goes to the line buffer. */
+            if (cwcNeeded > pLineBuf->u.Con.cwcBufAlloc)
             {
                 void *pvNew;
-                KU32  cwcNew = !pLineBuf->cwcBufAlloc ? 1024 : pLineBuf->cwcBufAlloc * 2;
+                KU32  cwcNew = !pLineBuf->u.Con.cwcBufAlloc ? 1024 : pLineBuf->u.Con.cwcBufAlloc * 2;
                 while (cwcNew < cwcNeeded)
                     cwcNew *= 2;
-                pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNew * sizeof(wchar_t));
+                pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNew * sizeof(wchar_t));
                 if (pvNew)
                 {
-                    pLineBuf->pwcBuf = (wchar_t *)pvNew;
-                    pLineBuf->cwcBufAlloc = cwcNew;
+                    pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew;
+                    pLineBuf->u.Con.cwcBufAlloc = cwcNew;
                 }
                 else
                 {
-                    pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNeeded * sizeof(wchar_t));
+                    pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNeeded * sizeof(wchar_t));
                     if (pvNew)
                     {
-                        pLineBuf->pwcBuf = (wchar_t *)pvNew;
-                        pLineBuf->cwcBufAlloc = cwcNeeded;
+                        pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew;
+                        pLineBuf->u.Con.cwcBufAlloc = cwcNeeded;
                     }
                     else
                     {
                         /* This isn't perfect, but it will have to do for now. */
-                        if (pLineBuf->cwcBuf > 0)
+                        if (pLineBuf->u.Con.cwcBuf > 0)
                         {
-                            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
-                            pLineBuf->cwcBuf = 0;
+                            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf,
+                                                          K_TRUE /*fBrokenLine*/);
+                            pLineBuf->u.Con.cwcBuf = 0;
                         }
                         kwSandboxConsoleAddToCombined(pSandbox, pwcBuffer, cwcToWrite, K_TRUE /*fBrokenLine*/);
                         return;
@@ -6015,27 +7370,28 @@ static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
              */
             if (offLastIncompleteLine == 0)
             {
-                memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t));
-                pLineBuf->cwcBuf += cwcToWrite;
+                kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t));
+                pLineBuf->u.Con.cwcBuf += cwcToWrite;
                 return;
             }
         }
 
         /*
-         * If there is sufficient combined buffer to handle this request, this are rather simple.
+         * If there is sufficient combined buffer to handle this request, this is rather simple.
          */
-        if (pLineBuf->cwcBuf + cchLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
+        kHlpAssert(pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf));
+        if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
         {
-            if (pLineBuf->cwcBuf > 0)
+            if (pLineBuf->u.Con.cwcBuf > 0)
             {
-                memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
-                       pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
-                pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
-                pLineBuf->cwcBuf = 0;
+                kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
+                            pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t));
+                pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf;
+                pLineBuf->u.Con.cwcBuf = 0;
             }
 
-            memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
-                   pwcBuffer, offLastIncompleteLine * sizeof(wchar_t));
+            kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
+                        pwcBuffer, offLastIncompleteLine * sizeof(wchar_t));
             pSandbox->Combined.cwcBuf += offLastIncompleteLine;
         }
         else
@@ -6047,39 +7403,40 @@ static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
             KU32 off = 0;
             KU32 offNextLine = 0;
 
-            /* If there is buffered chars, we handle the first line outside the
+            /* If there are buffered chars, we handle the first line outside the
                main loop.  We must try our best outputting it as a complete line. */
-            if (pLineBuf->cwcBuf > 0)
+            if (pLineBuf->u.Con.cwcBuf > 0)
             {
                 while (offNextLine < cwcToWrite && pwcBuffer[offNextLine] != '\n')
                     offNextLine++;
                 offNextLine++;
                 kHlpAssert(offNextLine <= offLastIncompleteLine);
 
-                if (pLineBuf->cwcBuf + offNextLine + pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf))
+                if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offNextLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
                 {
-                    memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
-                           pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
-                    pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
-                    pLineBuf->cwcBuf = 0;
+                    kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
+                                pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t));
+                    pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf;
+                    pLineBuf->u.Con.cwcBuf = 0;
 
-                    memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t));
+                    kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t));
                     pSandbox->Combined.cwcBuf += offNextLine;
                 }
                 else
                 {
-                    KU32 cwcLeft = pLineBuf->cwcBufAlloc - pLineBuf->cwcBuf;
+                    KU32 cwcLeft = pLineBuf->u.Con.cwcBufAlloc - pLineBuf->u.Con.cwcBuf;
                     if (cwcLeft > 0)
                     {
                         KU32 cwcCopy = K_MIN(cwcLeft, offNextLine);
-                        memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t));
-                        pLineBuf->cwcBuf += cwcCopy;
+                        kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t));
+                        pLineBuf->u.Con.cwcBuf += cwcCopy;
                         off += cwcCopy;
                     }
-                    if (pLineBuf->cwcBuf > 0)
+                    if (pLineBuf->u.Con.cwcBuf > 0)
                     {
-                        kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
-                        pLineBuf->cwcBuf = 0;
+                        kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf,
+                                                      K_TRUE /*fBrokenLine*/);
+                        pLineBuf->u.Con.cwcBuf = 0;
                     }
                     if (off < offNextLine)
                         kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_TRUE /*fBrokenLine*/);
@@ -6102,10 +7459,10 @@ static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
         /*
          * Buffer any remaining incomplete line chars.
          */
-        if (offLastIncompleteLine < cwcToWrite)
+        if (cchLastIncompleteLine)
         {
-            memcpy(&pLineBuf->pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t));
-            pLineBuf->cwcBuf = cchLastIncompleteLine;
+            kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t));
+            pLineBuf->u.Con.cwcBuf = cchLastIncompleteLine;
         }
     }
 }
@@ -6119,7 +7476,7 @@ static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
  * @param   pchBuffer           What to write.
  * @param   cchToWrite          How much to write.
  */
-static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite)
+static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite)
 {
     /*
      * Convert it to wide char and use the 'W' to do the work.
@@ -6128,6 +7485,7 @@ static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
     KU32        cwcBuf = cchToWrite * 2 + 1;
     wchar_t    *pwcBufFree = NULL;
     wchar_t    *pwcBuf;
+    kHlpAssert(pLineBuf->fIsConsole);
 
     if (cwcBuf <= 4096)
         pwcBuf = alloca(cwcBuf * sizeof(wchar_t));
@@ -6143,10 +7501,10 @@ static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
         kHlpAssertFailed();
 
         /* Flush the line buffer and combined buffer before calling WriteConsoleA. */
-        if (pLineBuf->cwcBuf > 0)
+        if (pLineBuf->u.Con.cwcBuf > 0)
         {
-            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBroken*/);
-            pLineBuf->cwcBuf = 0;
+            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBroken*/);
+            pLineBuf->u.Con.cwcBuf = 0;
         }
         kwSandboxConsoleFlushCombined(pSandbox);
 
@@ -6176,8 +7534,8 @@ static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLi
 BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cbToWrite, PDWORD pcbWritten,
                                              PVOID pvReserved)
 {
-    BOOL                    fRc;
-    PKWCONSOLEOUTPUTLINE    pLineBuf;
+    BOOL                fRc;
+    PKWOUTPUTSTREAMBUF  pLineBuf;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
     if (hConOutput == g_Sandbox.StdErr.hOutput)
@@ -6188,8 +7546,8 @@ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBu
     {
         kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (char const *)pvBuffer, cbToWrite);
 
-        KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
-                  hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
+        KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
+                   hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
         if (pcbWritten)
             *pcbWritten = cbToWrite;
         fRc = TRUE;
@@ -6197,8 +7555,8 @@ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBu
     else
     {
         fRc = WriteConsoleA(hConOutput, pvBuffer, cbToWrite, pcbWritten, pvReserved);
-        KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
-                  hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
+        KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
+                   hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
     }
     return fRc;
 }
@@ -6208,20 +7566,22 @@ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBu
 BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cwcToWrite, PDWORD pcwcWritten,
                                              PVOID pvReserved)
 {
-    BOOL                    fRc;
-    PKWCONSOLEOUTPUTLINE    pLineBuf;
+    BOOL                fRc;
+    PKWOUTPUTSTREAMBUF  pLineBuf;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
     if (hConOutput == g_Sandbox.StdErr.hOutput)
         pLineBuf = &g_Sandbox.StdErr;
-    else
+    else if (hConOutput == g_Sandbox.StdOut.hOutput)
         pLineBuf = &g_Sandbox.StdOut;
+    else
+        pLineBuf = g_Sandbox.StdErr.fIsConsole ? &g_Sandbox.StdErr : &g_Sandbox.StdOut;
     if (pLineBuf->fIsConsole)
     {
         kwSandboxConsoleWriteW(&g_Sandbox, pLineBuf, (wchar_t const *)pvBuffer, cwcToWrite);
 
-        KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
-                  hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
+        KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
+                   hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
         if (pcwcWritten)
             *pcwcWritten = cwcToWrite;
         fRc = TRUE;
@@ -6229,8 +7589,8 @@ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBu
     else
     {
         fRc = WriteConsoleW(hConOutput, pvBuffer, cwcToWrite, pcwcWritten, pvReserved);
-        KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
-                  hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
+        KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
+                   hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
     }
     return fRc;
 }
@@ -6247,36 +7607,133 @@ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBu
  *
  */
 
-/** Kernel32 - VirtualAlloc - for c1[xx].dll 78GB leaks.   */
+#ifdef WITH_FIXED_VIRTUAL_ALLOCS
+
+/** For debug logging.  */
+# ifndef NDEBUG
+static void kwSandboxLogFixedAllocation(KU32 idxFixed, const char *pszWhere)
+{
+    MEMORY_BASIC_INFORMATION MemInfo = { NULL, NULL, 0, 0, 0, 0, 0};
+    SIZE_T cbMemInfo = VirtualQuery(g_aFixedVirtualAllocs[idxFixed].pvReserved, &MemInfo, sizeof(MemInfo));
+    kHlpAssert(cbMemInfo == sizeof(MemInfo));
+    if (cbMemInfo != 0)
+        KW_LOG(("%s: #%u %p LB %#x: base=%p alloc=%p region=%#x state=%#x prot=%#x type=%#x\n",
+                pszWhere, idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed,
+                MemInfo.BaseAddress,
+                MemInfo.AllocationBase,
+                MemInfo.RegionSize,
+                MemInfo.State,
+                MemInfo.Protect,
+                MemInfo.Type));
+}
+# else
+#  define kwSandboxLogFixedAllocation(idxFixed, pszWhere) do { } while (0)
+# endif
+
+/**
+ * Used by both kwSandbox_Kernel32_VirtualFree and kwSandboxCleanupLate
+ *
+ * @param   idxFixed        The fixed allocation index to "free".
+ */
+static void kwSandboxResetFixedAllocation(KU32 idxFixed)
+{
+    BOOL fRc;
+    kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pre]");
+    fRc = VirtualFree(g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed, MEM_DECOMMIT);
+    kHlpAssert(fRc); K_NOREF(fRc);
+    kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pst]");
+    g_aFixedVirtualAllocs[idxFixed].fInUse = K_FALSE;
+}
+
+#endif /* WITH_FIXED_VIRTUAL_ALLOCS */
+
+
+/** Kernel32 - VirtualAlloc - for managing  cl.exe / c1[xx].dll heap with fixed
+ * location (~78MB in 32-bit 2010 compiler). */
 static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWORD fAllocType, DWORD fProt)
 {
-    PVOID pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
-    KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n",
-            pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()));
-    if (   g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
-        && pvMem)
+    PVOID pvMem;
+    if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
     {
-        PKWVIRTALLOC pTracker;
-        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+        KU32 idxPreAllocated = KU32_MAX;
+
+#ifdef WITH_FIXED_VIRTUAL_ALLOCS
+        /*
+         * Look for a pre-reserved CL.exe heap allocation.
+         */
+        pvMem = NULL;
+        if (   pvAddr != 0
+            && (fAllocType & MEM_RESERVE))
+        {
+            KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs);
+            kHlpAssert(!(fAllocType & ~(MEM_RESERVE | MEM_TOP_DOWN)));
+            while (idxFixed-- > 0)
+                if (   g_aFixedVirtualAllocs[idxFixed].uFixed == (KUPTR)pvAddr
+                    && g_aFixedVirtualAllocs[idxFixed].pvReserved)
+                {
+                    if (g_aFixedVirtualAllocs[idxFixed].cbFixed >= cb)
+                    {
+                        if (!g_aFixedVirtualAllocs[idxFixed].fInUse)
+                        {
+                            g_aFixedVirtualAllocs[idxFixed].fInUse = K_TRUE;
+                            pvMem                           = pvAddr;
+                            idxPreAllocated                 = idxFixed;
+                            KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p [pre allocated]\n",
+                                    pvAddr, cb, fAllocType, fProt, pvMem));
+                            kwSandboxLogFixedAllocation(idxFixed, "kwSandbox_Kernel32_VirtualAlloc");
+                            SetLastError(NO_ERROR);
+                            break;
+                        }
+                        kwErrPrintf("VirtualAlloc: Fixed allocation at %p is already in use!\n", pvAddr);
+                    }
+                    else
+                        kwErrPrintf("VirtualAlloc: Fixed allocation at %p LB %#x not large enough: %#x\n",
+                                     pvAddr, g_aFixedVirtualAllocs[idxFixed].cbFixed, cb);
+                }
+        }
+        if (!pvMem)
+#endif
+        {
+            pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
+            KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n",
+                    pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()));
+            if (pvAddr && pvAddr != pvMem)
+                kwErrPrintf("VirtualAlloc %p LB %#x (%#x,%#x) failed: %p / %u\n",
+                            pvAddr, cb, fAllocType, fProt, pvMem, GetLastError());
+        }
 
-        pTracker = g_Sandbox.pVirtualAllocHead;
-        while (   pTracker
-               && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc)
-            pTracker = pTracker->pNext;
-        if (!pTracker)
+        if (pvMem)
         {
-            DWORD dwErr = GetLastError();
-            PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker));
-            if (pTracker)
+            /* 
+             * Track it.
+             */
+            PKWVIRTALLOC pTracker;
+            kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+            pTracker = g_Sandbox.pVirtualAllocHead;
+            while (   pTracker
+                   && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc)
+                pTracker = pTracker->pNext;
+            if (!pTracker)
             {
-                pTracker->pvAlloc = pvMem;
-                pTracker->cbAlloc = cb;
-                pTracker->pNext   = g_Sandbox.pVirtualAllocHead;
-                g_Sandbox.pVirtualAllocHead = pTracker;
+                DWORD dwErr = GetLastError();
+                PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker));
+                if (pTracker)
+                {
+                    pTracker->pvAlloc           = pvMem;
+                    pTracker->cbAlloc           = cb;
+                    pTracker->idxPreAllocated   = idxPreAllocated;
+                    pTracker->pNext             = g_Sandbox.pVirtualAllocHead;
+                    g_Sandbox.pVirtualAllocHead = pTracker;
+                }
+                SetLastError(dwErr);
             }
-            SetLastError(dwErr);
         }
     }
+    else
+        pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
+    KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n",
+            pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()));
     return pvMem;
 }
 
@@ -6284,8 +7741,7 @@ static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWO
 /** Kernel32 - VirtualFree.   */
 static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD dwFreeType)
 {
-    BOOL fRc = VirtualFree(pvAddr, cb, dwFreeType);
-    KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
+    BOOL fRc;
     if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
     {
         kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
@@ -6308,12 +7764,57 @@ static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD
                         pPrev->pNext = pTracker->pNext;
                 }
                 if (pTracker)
-                    kHlpFree(pTracker);
-                else
-                    KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr));
+                {
+#ifdef WITH_FIXED_VIRTUAL_ALLOCS
+                    if (pTracker->idxPreAllocated != KU32_MAX)
+                    {
+                        kwSandboxResetFixedAllocation(pTracker->idxPreAllocated);
+                        KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> TRUE [pre allocated #%u]\n",
+                                pvAddr, cb, dwFreeType, pTracker->idxPreAllocated));
+                        kHlpFree(pTracker);
+                        return TRUE;
+                    }
+#endif
+
+                    fRc = VirtualFree(pvAddr, cb, dwFreeType);
+                    if (fRc)
+                        kHlpFree(pTracker);
+                    else
+                    {
+                        pTracker->pNext = g_Sandbox.pVirtualAllocHead;
+                        g_Sandbox.pVirtualAllocHead = pTracker;
+                    }
+                    KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
+                    return fRc;
+                }
+
+                KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr));
             }
         }
     }
+
+#ifdef WITH_FIXED_VIRTUAL_ALLOCS
+    /*
+     * Protect our fixed allocations (this isn't just paranoia, btw.).
+     */
+    if (dwFreeType & MEM_RELEASE)
+    {
+        KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs);
+        while (idxFixed-- > 0)
+            if (g_aFixedVirtualAllocs[idxFixed].pvReserved == pvAddr)
+            {
+                KW_LOG(("VirtualFree: Damn it! Don't free g_aFixedVirtualAllocs[#%u]: %p LB %#x\n",
+                        idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed));
+                return TRUE;
+            }
+    }
+#endif
+
+    /*
+     * Not tracker or not actually free the virtual range.
+     */
+    fRc = VirtualFree(pvAddr, cb, dwFreeType);
+    KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
     return fRc;
 }
 
@@ -6385,9 +7886,9 @@ BOOL WINAPI kwSandbox_Kernel32_HeapDestroy(HANDLE hHeap)
  * Thread/Fiber local storage leak prevention.
  * Thread/Fiber local storage leak prevention.
  *
- * Note! The FlsAlloc/Free causes problems for statically linked VS2010
- *       code like VBoxBs3ObjConverter.exe.  One thing is that we're
- *       leaking these indexes, but more importantely we crash during
+ * Note! The FlsAlloc/Free & TlsAlloc/Free causes problems for statically
+ *       linked VS2010 code like VBoxBs3ObjConverter.exe.  One thing is that
+ *       we're leaking these indexes, but more importantely we crash during
  *       worker exit since the callback is triggered multiple times.
  */
 
@@ -6450,6 +7951,64 @@ BOOL WINAPI kwSandbox_Kernel32_FlsFree(DWORD idxFls)
 }
 
 
+/** Kernel32 - TlsAlloc  */
+DWORD WINAPI kwSandbox_Kernel32_TlsAlloc(VOID)
+{
+    DWORD idxTls = TlsAlloc();
+    KW_LOG(("TlsAlloc() -> %#x\n", idxTls));
+    if (idxTls != TLS_OUT_OF_INDEXES)
+    {
+        PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker));
+        if (pTracker)
+        {
+            kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+            pTracker->idx = idxTls;
+            pTracker->pNext = g_Sandbox.pTlsAllocHead;
+            g_Sandbox.pTlsAllocHead = pTracker;
+        }
+    }
+
+    return idxTls;
+}
+
+/** Kernel32 - TlsFree */
+BOOL WINAPI kwSandbox_Kernel32_TlsFree(DWORD idxTls)
+{
+    BOOL fRc = TlsFree(idxTls);
+    KW_LOG(("TlsFree(%#x) -> %d\n", idxTls, fRc));
+    if (fRc)
+    {
+        PKWLOCALSTORAGE pTracker;
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+        pTracker = g_Sandbox.pTlsAllocHead;
+        if (pTracker)
+        {
+            if (pTracker->idx == idxTls)
+                g_Sandbox.pTlsAllocHead = pTracker->pNext;
+            else
+            {
+                PKWLOCALSTORAGE pPrev;
+                do
+                {
+                    pPrev = pTracker;
+                    pTracker = pTracker->pNext;
+                } while (pTracker && pTracker->idx != idxTls);
+                if (pTracker)
+                    pPrev->pNext = pTracker->pNext;
+            }
+            if (pTracker)
+            {
+                pTracker->idx   = TLS_OUT_OF_INDEXES;
+                pTracker->pNext = NULL;
+                kHlpFree(pTracker);
+            }
+        }
+    }
+    return fRc;
+}
+
+
 
 /*
  *
@@ -6465,7 +8024,7 @@ BOOL WINAPI kwSandbox_Kernel32_FlsFree(DWORD idxFls)
 
 #ifdef WITH_HASH_MD5_CACHE
 
-/** Advapi32 - CryptCreateHash */
+/** AdvApi32 - CryptCreateHash */
 static BOOL WINAPI kwSandbox_Advapi32_CryptCreateHash(HCRYPTPROV hProv, ALG_ID idAlg, HCRYPTKEY hKey, DWORD dwFlags,
                                                       HCRYPTHASH *phHash)
 {
@@ -6524,7 +8083,7 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptCreateHash(HCRYPTPROV hProv, ALG_ID i
 }
 
 
-/** Advapi32 - CryptHashData */
+/** AdvApi32 - CryptHashData */
 static BOOL WINAPI kwSandbox_Advapi32_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD cbData, DWORD dwFlags)
 {
     BOOL        fRc;
@@ -6639,7 +8198,7 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptHashData(HCRYPTHASH hHash, CONST BYTE
 }
 
 
-/** Advapi32 - CryptGetHashParam */
+/** AdvApi32 - CryptGetHashParam */
 static BOOL WINAPI kwSandbox_Advapi32_CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam,
                                                         BYTE *pbData, DWORD *pcbData, DWORD dwFlags)
 {
@@ -6797,7 +8356,7 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptGetHashParam(HCRYPTHASH hHash, DWORD
 }
 
 
-/** Advapi32 - CryptDestroyHash */
+/** AdvApi32 - CryptDestroyHash */
 static BOOL WINAPI kwSandbox_Advapi32_CryptDestroyHash(HCRYPTHASH hHash)
 {
     BOOL        fRc;
@@ -6846,6 +8405,341 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptDestroyHash(HCRYPTHASH hHash)
 
 /*
  *
+ * Reuse crypt context.
+ * Reuse crypt context.
+ * Reuse crypt context.
+ *
+ *
+ * This saves a little bit of time and registry accesses each time CL, C1 or C1XX runs.
+ *
+ */
+
+#ifdef WITH_CRYPT_CTX_REUSE
+
+/** AdvApi32 - CryptAcquireContextW.  */
+static BOOL WINAPI kwSandbox_Advapi32_CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider,
+                                                           DWORD dwProvType,  DWORD dwFlags)
+{
+    BOOL fRet;
+
+    /*
+     * Lookup reusable context based on the input.
+     */
+    KSIZE const cwcContainer = pwszContainer ? kwUtf16Len(pwszContainer) : 0;
+    KSIZE const cwcProvider  = pwszProvider  ? kwUtf16Len(pwszProvider) : 0;
+    KU32        iCtx = g_Sandbox.cCryptCtxs;
+    while (iCtx-- > 0)
+    {
+        if (   g_Sandbox.aCryptCtxs[iCtx].cwcContainer == cwcContainer
+            && g_Sandbox.aCryptCtxs[iCtx].cwcProvider  == cwcProvider
+            && g_Sandbox.aCryptCtxs[iCtx].dwProvType   == dwProvType
+            && g_Sandbox.aCryptCtxs[iCtx].dwFlags      == dwFlags
+            && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszContainer, pwszContainer, cwcContainer * sizeof(wchar_t)) == 0
+            && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszProvider,  pwszProvider,  cwcProvider  * sizeof(wchar_t)) == 0)
+        {
+            if (CryptContextAddRef(g_Sandbox.aCryptCtxs[iCtx].hProv, NULL, 0))
+            {
+                *phProv = g_Sandbox.aCryptCtxs[iCtx].hProv;
+                KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [reused]\n",
+                             pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv));
+                return TRUE;
+            }
+        }
+    }
+
+    /*
+     * Create it and enter it into the reused array if possible.
+     */
+    fRet = CryptAcquireContextW(phProv, pwszContainer, pwszProvider, dwProvType, dwFlags);
+    if (fRet)
+    {
+        iCtx = g_Sandbox.cCryptCtxs;
+        if (iCtx < K_ELEMENTS(g_Sandbox.aCryptCtxs))
+        {
+            /* Try duplicate the input strings. */
+            g_Sandbox.aCryptCtxs[iCtx].pwszContainer = kHlpDup(pwszContainer ? pwszContainer : L"",
+                                                               (cwcContainer + 1) * sizeof(wchar_t));
+            if (g_Sandbox.aCryptCtxs[iCtx].pwszContainer)
+            {
+                g_Sandbox.aCryptCtxs[iCtx].pwszProvider  = kHlpDup(pwszProvider ? pwszProvider : L"",
+                                                                   (cwcProvider + 1) * sizeof(wchar_t));
+                if (g_Sandbox.aCryptCtxs[iCtx].pwszProvider)
+                {
+                    /* Add a couple of references just to be on the safe side and all that. */
+                    HCRYPTPROV hProv = *phProv;
+                    if (CryptContextAddRef(hProv, NULL, 0))
+                    {
+                        if (CryptContextAddRef(hProv, NULL, 0))
+                        {
+                            /* Okay, finish the entry and return success */
+                            g_Sandbox.aCryptCtxs[iCtx].hProv      = hProv;
+                            g_Sandbox.aCryptCtxs[iCtx].dwProvType = dwProvType;
+                            g_Sandbox.aCryptCtxs[iCtx].dwFlags    = dwFlags;
+                            g_Sandbox.cCryptCtxs = iCtx + 1;
+
+                            KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [new]\n",
+                                         pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv));
+                            return TRUE;
+                        }
+                        CryptReleaseContext(hProv, 0);
+                    }
+                    KWCRYPT_LOG(("CryptAcquireContextW: CryptContextAddRef failed!\n"));
+
+                    kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszProvider);
+                    g_Sandbox.aCryptCtxs[iCtx].pwszProvider = NULL;
+                }
+                kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszContainer);
+                g_Sandbox.aCryptCtxs[iCtx].pwszContainer = NULL;
+            }
+        }
+        else
+            KWCRYPT_LOG(("CryptAcquireContextW: Too many crypt contexts to keep and reuse!\n"));
+    }
+
+    KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> %d, %p\n",
+                 pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv));
+    return fRet;
+}
+
+
+/** AdvApi32 - CryptReleaseContext */
+static BOOL WINAPI kwSandbox_Advapi32_CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
+{
+    BOOL fRet = CryptReleaseContext(hProv, dwFlags);
+    KWCRYPT_LOG(("CryptReleaseContext(%p,%#x) -> %d\n", hProv, dwFlags, fRet));
+    return fRet;
+}
+
+
+/** AdvApi32 - CryptContextAddRef  */
+static BOOL WINAPI kwSandbox_Advapi32_CryptContextAddRef(HCRYPTPROV hProv, DWORD *pdwReserved, DWORD dwFlags)
+{
+    BOOL fRet = CryptContextAddRef(hProv, pdwReserved, dwFlags);
+    KWCRYPT_LOG(("CryptContextAddRef(%p,%p,%#x) -> %d\n", hProv, pdwReserved, dwFlags, fRet));
+    return fRet;
+}
+
+#endif /* WITH_CRYPT_CTX_REUSE */
+
+/*
+ *
+ * Structured exception handling.
+ * Structured exception handling.
+ * Structured exception handling.
+ *
+ */
+#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
+
+# define EH_NONCONTINUABLE      KU32_C(0x00000001)
+# define EH_UNWINDING           KU32_C(0x00000002)
+# define EH_EXIT_UNWIND         KU32_C(0x00000004)
+# define EH_STACK_INVALID       KU32_C(0x00000008)
+# define EH_NESTED_CALL         KU32_C(0x00000010)
+
+typedef KU32 (__cdecl * volatile PFNXCPTHANDLER)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT,
+                                                 struct _EXCEPTION_REGISTRATION_RECORD * volatile *);
+typedef struct _EXCEPTION_REGISTRATION_RECORD
+{
+    struct _EXCEPTION_REGISTRATION_RECORD * volatile    pPrevRegRec;
+    PFNXCPTHANDLER                                      pfnXcptHandler;
+};
+
+
+/**
+ * Calls @a pfnHandler.
+ */
+static KU32 kwSandboxXcptCallHandler(PEXCEPTION_RECORD pXcptRec, struct _EXCEPTION_REGISTRATION_RECORD *pRegRec,
+                                     PCONTEXT pXcptCtx, struct _EXCEPTION_REGISTRATION_RECORD * volatile * ppRegRec,
+                                     PFNXCPTHANDLER pfnHandler)
+{
+# if 1
+    /* This is a more robust version that isn't subject to calling
+       convension cleanup disputes and such. */
+    KU32 uSavedEdi;
+    KU32 uSavedEsi;
+    KU32 uSavedEbx;
+    KU32 rcHandler;
+
+    __asm
+    {
+        mov     [uSavedEdi], edi
+        mov     [uSavedEsi], esi
+        mov     [uSavedEbx], ebx
+        mov     esi, esp
+        mov     edi, esp
+        mov     edi, [pXcptRec]
+        mov     edx, [pRegRec]
+        mov     eax, [pXcptCtx]
+        mov     ebx, [ppRegRec]
+        mov     ecx, [pfnHandler]
+        sub     esp, 16
+        and     esp, 0fffffff0h
+        mov     [esp     ], edi
+        mov     [esp +  4], edx
+        mov     [esp +  8], eax
+        mov     [esp + 12], ebx
+        mov     edi, esi
+        call    ecx
+        mov     esp, esi
+        cmp     esp, edi
+        je      stack_ok
+        int     3
+    stack_ok:
+        mov     edi, [uSavedEdi]
+        mov     esi, [uSavedEsi]
+        mov     ebx, [uSavedEbx]
+        mov     [rcHandler], eax
+    }
+    return rcHandler;
+# else
+    return pfnHandler(pXcptRec, pRegRec, pXctpCtx, ppRegRec);
+# endif
+}
+
+
+/**
+ * Vectored exception handler that emulates x86 chained exception handler.
+ *
+ * This is necessary because the RtlIsValidHandler check fails for self loaded
+ * code and prevents cl.exe from working.  (On AMD64 we can register function
+ * tables, but on X86 cooking your own handling seems to be the only viabke
+ * alternative.)
+ *
+ * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION.
+ * @param   pXcptPtrs           The exception details.
+ */
+static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs)
+{
+    PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
+    KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode));
+    if (g_Sandbox.fRunning)
+    {
+        HANDLE const                                      hCurProc = GetCurrentProcess();
+        PEXCEPTION_RECORD                                 pXcptRec = pXcptPtrs->ExceptionRecord;
+        PCONTEXT                                          pXcptCtx = pXcptPtrs->ContextRecord;
+        struct _EXCEPTION_REGISTRATION_RECORD *           pRegRec  = pTib->ExceptionList;
+        while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL)
+        {
+            /* Read the exception record in a safe manner. */
+            struct _EXCEPTION_REGISTRATION_RECORD   RegRec;
+            DWORD                                   cbActuallyRead = 0;
+            if (   ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead)
+                && cbActuallyRead == sizeof(RegRec))
+            {
+                struct _EXCEPTION_REGISTRATION_RECORD * volatile    pDispRegRec = NULL;
+                KU32                                                rcHandler;
+                KW_LOG(("kwSandboxVecXcptEmulateChained: calling %p, pRegRec=%p, pPrevRegRec=%p\n",
+                        RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec));
+                rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler);
+                KW_LOG(("kwSandboxVecXcptEmulateChained: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec));
+                if (rcHandler == ExceptionContinueExecution)
+                {
+                    kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE));
+                    KW_LOG(("kwSandboxVecXcptEmulateChained: returning EXCEPTION_CONTINUE_EXECUTION!\n"));
+                    return EXCEPTION_CONTINUE_EXECUTION;
+                }
+
+                if (rcHandler == ExceptionContinueSearch)
+                    kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
+                else if (rcHandler == ExceptionNestedException)
+                    kHlpAssertMsgFailed(("Nested exceptions.\n"));
+                else
+                    kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
+            }
+            else
+            {
+                KW_LOG(("kwSandboxVecXcptEmulateChained: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec));
+                break;
+            }
+
+            /*
+             * Next.
+             */
+            pRegRec = RegRec.pPrevRegRec;
+        }
+    }
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+
+
+/** NtDll,Kernel32 - RtlUnwind */
+static VOID WINAPI kwSandbox_ntdll_RtlUnwind(struct _EXCEPTION_REGISTRATION_RECORD *pStopXcptRec, PVOID pvTargetIp,
+                                             PEXCEPTION_RECORD pXcptRec, PVOID pvReturnValue)
+{
+    PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
+    KW_LOG(("kwSandbox_ntdll_RtlUnwind: pStopXcptRec=%p pvTargetIp=%p pXctpRec=%p pvReturnValue=%p%s\n",
+            pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue, g_Sandbox.fRunning ? "" : " [sandbox not running]"));
+    if (g_Sandbox.fRunning)
+    {
+        HANDLE const                                      hCurProc = GetCurrentProcess();
+        PCONTEXT                                          pXcptCtx = NULL;
+        struct _EXCEPTION_REGISTRATION_RECORD *           pRegRec  = pTib->ExceptionList;
+
+        /*
+         * Update / create an exception record.
+         */
+        if (pXcptRec)
+            pXcptRec->ExceptionFlags |= EH_UNWINDING;
+        else
+        {
+            pXcptRec = (PEXCEPTION_RECORD)alloca(sizeof(*pXcptRec));
+            kHlpMemSet(pXcptRec, 0, sizeof(*pXcptRec));
+            pXcptRec->ExceptionCode  = STATUS_UNWIND;
+            pXcptRec->ExceptionFlags = EH_UNWINDING;
+        }
+        if (!pStopXcptRec)
+            pXcptRec->ExceptionFlags |= EH_EXIT_UNWIND;
+
+        /*
+         * Walk the chain till we find pStopXctpRec.
+         */
+        while (   ((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0
+               && pRegRec != NULL
+               && pRegRec != pStopXcptRec)
+        {
+            /* Read the exception record in a safe manner. */
+            struct _EXCEPTION_REGISTRATION_RECORD   RegRec;
+            DWORD                                   cbActuallyRead = 0;
+            if (   ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead)
+                && cbActuallyRead == sizeof(RegRec))
+            {
+                struct _EXCEPTION_REGISTRATION_RECORD * volatile    pDispRegRec = NULL;
+                KU32                                                rcHandler;
+                KW_LOG(("kwSandbox_ntdll_RtlUnwind: calling %p, pRegRec=%p, pPrevRegRec=%p\n",
+                        RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec));
+                rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler);
+                KW_LOG(("kwSandbox_ntdll_RtlUnwind: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec));
+
+                if (rcHandler == ExceptionContinueSearch)
+                    kHlpAssert(!(pXcptRec->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
+                else if (rcHandler == ExceptionCollidedUnwind)
+                    kHlpAssertMsgFailed(("Implement collided unwind!\n"));
+                else
+                    kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
+            }
+            else
+            {
+                KW_LOG(("kwSandbox_ntdll_RtlUnwind: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec));
+                break;
+            }
+
+            /*
+             * Pop next.
+             */
+            pTib->ExceptionList = RegRec.pPrevRegRec;
+            pRegRec = RegRec.pPrevRegRec;
+        }
+        return;
+    }
+
+    RtlUnwind(pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue);
+}
+
+#endif /* WINDOWS + X86 */
+
+
+/*
+ *
  * Misc function only intercepted while debugging.
  * Misc function only intercepted while debugging.
  * Misc function only intercepted while debugging.
@@ -6924,10 +8818,12 @@ KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
     { TUPLE("GetFileSizeEx"),               NULL,       (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
     { TUPLE("CreateFileMappingW"),          NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
     { TUPLE("MapViewOfFile"),               NULL,       (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
+    { TUPLE("MapViewOfFileEx"),             NULL,       (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx },
     { TUPLE("UnmapViewOfFile"),             NULL,       (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
 #endif
     { TUPLE("SetFilePointer"),              NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointer },
     { TUPLE("SetFilePointerEx"),            NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
+    { TUPLE("DuplicateHandle"),             NULL,       (KUPTR)kwSandbox_Kernel32_DuplicateHandle },
     { TUPLE("CloseHandle"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CloseHandle },
     { TUPLE("GetFileAttributesA"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
     { TUPLE("GetFileAttributesW"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
@@ -6945,11 +8841,17 @@ KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
     { TUPLE("HeapCreate"),                  NULL,       (KUPTR)kwSandbox_Kernel32_HeapCreate,       K_TRUE /*fOnlyExe*/ },
     { TUPLE("HeapDestroy"),                 NULL,       (KUPTR)kwSandbox_Kernel32_HeapDestroy,      K_TRUE /*fOnlyExe*/ },
 
-    { TUPLE("FlsAlloc"),                    NULL,       (KUPTR)kwSandbox_Kernel32_FlsAlloc },
-    { TUPLE("FlsFree"),                     NULL,       (KUPTR)kwSandbox_Kernel32_FlsFree },
+    { TUPLE("FlsAlloc"),                    NULL,       (KUPTR)kwSandbox_Kernel32_FlsAlloc,         K_TRUE /*fOnlyExe*/ },
+    { TUPLE("FlsFree"),                     NULL,       (KUPTR)kwSandbox_Kernel32_FlsFree,          K_TRUE /*fOnlyExe*/ },
+    { TUPLE("TlsAlloc"),                    NULL,       (KUPTR)kwSandbox_Kernel32_TlsAlloc,         K_TRUE /*fOnlyExe*/ },
+    { TUPLE("TlsFree"),                     NULL,       (KUPTR)kwSandbox_Kernel32_TlsFree,          K_TRUE /*fOnlyExe*/ },
 
     { TUPLE("SetConsoleCtrlHandler"),       NULL,       (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler },
 
+#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
+    { TUPLE("RtlUnwind"),                   NULL,       (KUPTR)kwSandbox_ntdll_RtlUnwind },
+#endif
+
 #ifdef WITH_HASH_MD5_CACHE
     { TUPLE("CryptCreateHash"),             NULL,       (KUPTR)kwSandbox_Advapi32_CryptCreateHash },
     { TUPLE("CryptHashData"),               NULL,       (KUPTR)kwSandbox_Advapi32_CryptHashData },
@@ -6957,6 +8859,12 @@ KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
     { TUPLE("CryptDestroyHash"),            NULL,       (KUPTR)kwSandbox_Advapi32_CryptDestroyHash },
 #endif
 
+#ifdef WITH_CRYPT_CTX_REUSE
+    { TUPLE("CryptAcquireContextW"),        NULL,       (KUPTR)kwSandbox_Advapi32_CryptAcquireContextW },
+    { TUPLE("CryptReleaseContext"),         NULL,       (KUPTR)kwSandbox_Advapi32_CryptReleaseContext },
+    { TUPLE("CryptContextAddRef"),          NULL,       (KUPTR)kwSandbox_Advapi32_CryptContextAddRef },
+#endif
+
     /*
      * MS Visual C++ CRTs.
      */
@@ -7047,10 +8955,12 @@ KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] =
     { TUPLE("GetFileSizeEx"),               NULL,       (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
     { TUPLE("CreateFileMappingW"),          NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
     { TUPLE("MapViewOfFile"),               NULL,       (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
+    { TUPLE("MapViewOfFileEx"),             NULL,       (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx },
     { TUPLE("UnmapViewOfFile"),             NULL,       (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
 #endif
     { TUPLE("SetFilePointer"),              NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointer },
     { TUPLE("SetFilePointerEx"),            NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
+    { TUPLE("DuplicateHandle"),             NULL,       (KUPTR)kwSandbox_Kernel32_DuplicateHandle },
     { TUPLE("CloseHandle"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CloseHandle },
     { TUPLE("GetFileAttributesA"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
     { TUPLE("GetFileAttributesW"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
@@ -7072,6 +8982,9 @@ KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] =
 
     { TUPLE("RtlPcToFileHeader"),           NULL,       (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader },
 
+#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
+    { TUPLE("RtlUnwind"),                   NULL,       (KUPTR)kwSandbox_ntdll_RtlUnwind },
+#endif
 
     /*
      * MS Visual C++ CRTs.
@@ -7093,6 +9006,23 @@ KU32 const                  g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandbox
 
 
 /**
+ * Functions that needs replacing when queried by GetProcAddress.
+ */
+KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[] =
+{
+    /*
+     * Kernel32.dll and friends.
+     */
+    { TUPLE("FlsAlloc"),                    NULL,       (KUPTR)kwSandbox_Kernel32_FlsAlloc, K_TRUE /*fOnlyExe*/ },
+    { TUPLE("FlsFree"),                     NULL,       (KUPTR)kwSandbox_Kernel32_FlsFree,  K_TRUE /*fOnlyExe*/ },
+    { TUPLE("TlsAlloc"),                    NULL,       (KUPTR)kwSandbox_Kernel32_TlsAlloc, K_TRUE /*fOnlyExe*/ },
+    { TUPLE("TlsFree"),                     NULL,       (KUPTR)kwSandbox_Kernel32_TlsFree,  K_TRUE /*fOnlyExe*/ },
+};
+/** Number of entries in g_aSandboxGetProcReplacements. */
+KU32 const                  g_cSandboxGetProcReplacements = K_ELEMENTS(g_aSandboxGetProcReplacements);
+
+
+/**
  * Control handler.
  *
  * @returns TRUE if handled, FALSE if not.
@@ -7104,26 +9034,31 @@ static BOOL WINAPI kwSandboxCtrlHandler(DWORD dwCtrlType)
     {
         case CTRL_C_EVENT:
             fprintf(stderr, "kWorker: Ctrl-C\n");
+            g_fCtrlC = K_TRUE;
             exit(9);
             break;
 
         case CTRL_BREAK_EVENT:
             fprintf(stderr, "kWorker: Ctrl-Break\n");
+            g_fCtrlC = K_TRUE;
             exit(10);
             break;
 
         case CTRL_CLOSE_EVENT:
             fprintf(stderr, "kWorker: console closed\n");
+            g_fCtrlC = K_TRUE;
             exit(11);
             break;
 
         case CTRL_LOGOFF_EVENT:
             fprintf(stderr, "kWorker: logoff event\n");
+            g_fCtrlC = K_TRUE;
             exit(11);
             break;
 
         case CTRL_SHUTDOWN_EVENT:
             fprintf(stderr, "kWorker: shutdown event\n");
+            g_fCtrlC = K_TRUE;
             exit(11);
             break;
 
@@ -7167,109 +9102,18 @@ static PPEB kwSandboxGetProcessEnvironmentBlock(void)
 }
 
 
-#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
-typedef struct _EXCEPTION_REGISTRATION_RECORD
-{
-    struct _EXCEPTION_REGISTRATION_RECORD * volatile PrevStructure;
-    KU32 (__cdecl * volatile ExceptionHandler)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT,
-                                               struct _EXCEPTION_REGISTRATION_RECORD * volatile *);
-};
-
-/**
- * Vectored exception handler that emulates x86 chained exception handler.
- *
- * This is necessary because the RtlIsValidHandler check fails for self loaded
- * code and prevents cl.exe from working.  (On AMD64 we can register function
- * tables, but on X86 cooking your own handling seems to be the only viabke
- * alternative.)
- *
- * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION.
- * @param   pXcptPtrs           The exception details.
- */
-static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs)
-{
-    PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
-    KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode));
-    if (g_Sandbox.fRunning)
-    {
-        PEXCEPTION_RECORD                                 pXcptRec = pXcptPtrs->ExceptionRecord;
-        PCONTEXT                                          pXcptCtx = pXcptPtrs->ContextRecord;
-        struct _EXCEPTION_REGISTRATION_RECORD * volatile *ppRegRec = &pTib->ExceptionList;
-        struct _EXCEPTION_REGISTRATION_RECORD *           pRegRec  = *ppRegRec;
-        while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL)
-        {
-#if 1
-            /* This is a more robust version that isn't subject to calling
-               convension cleanup disputes and such. */
-            KU32 uSavedEdi;
-            KU32 uSavedEsi;
-            KU32 uSavedEbx;
-            KU32 rcHandler;
-            __asm
-            {
-                mov     [uSavedEdi], edi
-                mov     [uSavedEsi], esi
-                mov     [uSavedEbx], ebx
-                mov     esi, esp
-                mov     edi, esp
-                mov     ecx, [pXcptRec]
-                mov     edx, [pRegRec]
-                mov     eax, [pXcptCtx]
-                mov     ebx, [ppRegRec]
-                sub     esp, 16
-                and     esp, 0fffffff0h
-                mov     [esp     ], ecx
-                mov     [esp +  4], edx
-                mov     [esp +  8], eax
-                mov     [esp + 12], ebx
-                call    dword ptr [edx + 4]
-                mov     esp, esi
-                cmp     esp, edi
-                je      stack_ok
-                int     3
-            stack_ok:
-                mov     edi, [uSavedEdi]
-                mov     esi, [uSavedEsi]
-                mov     ebx, [uSavedEbx]
-                mov     [rcHandler], eax
-            }
-#else
-            KU32 rcHandler = pRegRec->ExceptionHandler(pXcptPtrs->ExceptionRecord, pRegRec, pXcptPtrs->ContextRecord, ppRegRec);
-#endif
-            if (rcHandler == ExceptionContinueExecution)
-            {
-                kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE));
-                return EXCEPTION_CONTINUE_EXECUTION;
-            }
-            if (rcHandler == ExceptionContinueSearch)
-                kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
-            else if (rcHandler == ExceptionNestedException)
-                kHlpAssertMsgFailed(("Nested exceptions.\n"));
-            else
-                kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
-
-            /*
-             * Next.
-             */
-            ppRegRec = &pRegRec->PrevStructure;
-            pRegRec = pRegRec->PrevStructure;
-        }
-    }
-    return EXCEPTION_CONTINUE_SEARCH;
-}
-#endif /* WINDOWS + X86 */
-
-
 /**
  * Enters the given handle into the handle table.
  *
  * @returns K_TRUE on success, K_FALSE on failure.
  * @param   pSandbox            The sandbox.
  * @param   pHandle             The handle.
+ * @param   hHandle             The handle value to enter it under (for the
+ *                              duplicate handle API).
  */
-static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle)
+static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle)
 {
-    KUPTR const idxHandle = KW_HANDLE_TO_INDEX(pHandle->hHandle);
+    KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hHandle);
     kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE);
 
     /*
@@ -7359,15 +9203,15 @@ static char *kwSandboxInitCmdLineFromArgv(KU32 cArgs, const char **papszArgs, KB
 
 static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
                          KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
-                         KU32 cEnvVars, const char **papszEnvVars)
+                         KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching)
 {
     PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
+    PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
     wchar_t *pwcPool;
     KSIZE cbStrings;
     KSIZE cwc;
     KSIZE cbCmdLine;
     KU32 i;
-    int rc;
 
     /* Simple stuff. */
     pSandbox->rcExitCode    = 256;
@@ -7376,11 +9220,18 @@ static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
     pSandbox->pgmptr        = (char *)pTool->pszPath;
     pSandbox->wpgmptr       = (wchar_t *)pTool->pwszPath;
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
-    pSandbox->StdOut.cwcBuf = 0;
-    pSandbox->StdErr.cwcBuf = 0;
-    pSandbox->Combined.cwcBuf = 0;
+    if (pSandbox->StdOut.fIsConsole)
+        pSandbox->StdOut.u.Con.cwcBuf   = 0;
+    else
+        pSandbox->StdOut.u.Fully.cchBuf = 0;
+    if (pSandbox->StdErr.fIsConsole)
+        pSandbox->StdErr.u.Con.cwcBuf   = 0;
+    else
+        pSandbox->StdErr.u.Fully.cchBuf = 0;
+    pSandbox->Combined.cwcBuf   = 0;
     pSandbox->Combined.cFlushes = 0;
 #endif
+    pSandbox->fNoPchCaching = fNoPchCaching;
     pSandbox->cArgs         = cArgs;
     pSandbox->papszArgs     = (char **)papszArgs;
     pSandbox->pszCmdLine    = kwSandboxInitCmdLineFromArgv(cArgs, papszArgs, fWatcomBrainDamange, &cbCmdLine);
@@ -7414,15 +9265,15 @@ static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
         return KERR_NO_MEMORY;
     cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
 
-    pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
-    pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
-    pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
+    pSandbox->SavedCommandLine = pProcParams->CommandLine;
+    pProcParams->CommandLine.Buffer = pSandbox->pwszCmdLine;
+    pProcParams->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
 
     /*
-     * Setup the enviornment.
+     * Setup the environment.
      */
-    rc = kwSandboxGrowEnv(pSandbox, cEnvVars + 2);
-    if (rc == 0)
+    if (   cEnvVars + 2 <= pSandbox->cEnvVarsAllocated
+        || kwSandboxGrowEnv(pSandbox, cEnvVars + 2) == 0)
     {
         KU32 iDst = 0;
         for (i = 0; i < cEnvVars; i++)
@@ -7458,13 +9309,24 @@ static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
         pSandbox->wenviron[iDst]      = NULL;
     }
     else
-        return kwErrPrintfRc(KERR_NO_MEMORY, "Error setting up environment variables: %d\n", rc);
+        return kwErrPrintfRc(KERR_NO_MEMORY, "Error setting up environment variables: kwSandboxGrowEnv failed\n");
+
 
     /*
      * Invalidate the volatile parts of cache (kBuild output directory,
      * temporary directory, whatever).
      */
     kFsCacheInvalidateCustomBoth(g_pFsCache);
+
+#ifdef WITH_HISTORY
+    /*
+     * Record command line in debug history.
+     */
+    kHlpFree(g_apszHistory[g_iHistoryNext]);
+    g_apszHistory[g_iHistoryNext] = kHlpStrDup(pSandbox->pszCmdLine);
+    g_iHistoryNext = (g_iHistoryNext + 1) % K_ELEMENTS(g_apszHistory);
+#endif
+
     return 0;
 }
 
@@ -7491,6 +9353,10 @@ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
 #endif
     PKWEXITCALLACK              pExitCallback;
 
+    /*
+     * First stuff that may cause code to run.
+     */
+
     /* Do exit callback first. */
     pExitCallback = g_Sandbox.pExitCallbackHead;
     g_Sandbox.pExitCallbackHead = NULL;
@@ -7513,6 +9379,89 @@ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
         pExitCallback = pNext;
     }
 
+    /* Free left behind FlsAlloc leaks. */
+    pLocalStorage = g_Sandbox.pFlsAllocHead;
+    g_Sandbox.pFlsAllocHead = NULL;
+    while (pLocalStorage)
+    {
+        PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
+        KW_LOG(("Freeing leaked FlsAlloc index %#x\n", pLocalStorage->idx));
+        FlsFree(pLocalStorage->idx);
+        kHlpFree(pLocalStorage);
+        pLocalStorage = pNext;
+    }
+
+    /* Free left behind TlsAlloc leaks. */
+    pLocalStorage = g_Sandbox.pTlsAllocHead;
+    g_Sandbox.pTlsAllocHead = NULL;
+    while (pLocalStorage)
+    {
+        PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
+        KW_LOG(("Freeing leaked TlsAlloc index %#x\n", pLocalStorage->idx));
+        TlsFree(pLocalStorage->idx);
+        kHlpFree(pLocalStorage);
+        pLocalStorage = pNext;
+    }
+
+
+    /*
+     * Then free resources associated with the sandbox run.
+     */
+
+    /* Open handles, except fixed handles (stdout and stderr). */
+    if (pSandbox->cActiveHandles > pSandbox->cFixedHandles)
+    {
+        KU32 idxHandle = pSandbox->cHandles;
+        while (idxHandle-- > 0)
+            if (pSandbox->papHandles[idxHandle] == NULL)
+            { /* likely */ }
+            else
+            {
+                PKWHANDLE pHandle = pSandbox->papHandles[idxHandle];
+                if (   pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF
+                    || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle) )
+                {
+                    pSandbox->papHandles[idxHandle] = NULL;
+                    pSandbox->cLeakedHandles++;
+
+                    switch (pHandle->enmType)
+                    {
+                        case KWHANDLETYPE_FSOBJ_READ_CACHE:
+                            KWFS_LOG(("Closing leaked read cache handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            break;
+                        case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING:
+                            KWFS_LOG(("Closing leaked read mapping handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            break;
+                        case KWHANDLETYPE_OUTPUT_BUF:
+                            KWFS_LOG(("Closing leaked output buf handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            break;
+                        case KWHANDLETYPE_TEMP_FILE:
+                            KWFS_LOG(("Closing leaked temp file  handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            pHandle->u.pTempFile->cActiveHandles--;
+                            break;
+                        case KWHANDLETYPE_TEMP_FILE_MAPPING:
+                            KWFS_LOG(("Closing leaked temp mapping handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            pHandle->u.pTempFile->cActiveHandles--;
+                            break;
+                        default:
+                            kHlpAssertFailed();
+                    }
+                    if (--pHandle->cRefs == 0)
+                        kHlpFree(pHandle);
+                    if (--pSandbox->cActiveHandles == pSandbox->cFixedHandles)
+                        break;
+                }
+            }
+        kHlpAssert(pSandbox->cActiveHandles == pSandbox->cFixedHandles);
+    }
+
+    /* Reset memory mappings - This assumes none of the DLLs keeps any of our mappings open! */
+    g_Sandbox.cMemMappings = 0;
 
 #ifdef WITH_TEMP_MEMORY_FILES
     /* The temporary files aren't externally visible, they're all in memory. */
@@ -7532,18 +9481,6 @@ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
     }
 #endif
 
-    /* Free left behind VirtualAlloc leaks. */
-    pTracker = g_Sandbox.pVirtualAllocHead;
-    g_Sandbox.pVirtualAllocHead = NULL;
-    while (pTracker)
-    {
-        PKWVIRTALLOC pNext = pTracker->pNext;
-        KW_LOG(("Freeing VirtualFree leak %p LB %#x\n", pTracker->pvAlloc, pTracker->cbAlloc));
-        VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE);
-        kHlpFree(pTracker);
-        pTracker = pNext;
-    }
-
     /* Free left behind HeapCreate leaks. */
     pHeap = g_Sandbox.pHeapHead;
     g_Sandbox.pHeapHead = NULL;
@@ -7555,31 +9492,24 @@ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
         pHeap = pNext;
     }
 
-    /* Free left behind FlsAlloc leaks. */
-    pLocalStorage = g_Sandbox.pFlsAllocHead;
-    g_Sandbox.pFlsAllocHead = NULL;
-    while (pLocalStorage)
+    /* Free left behind VirtualAlloc leaks. */
+    pTracker = g_Sandbox.pVirtualAllocHead;
+    g_Sandbox.pVirtualAllocHead = NULL;
+    while (pTracker)
     {
-        PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
-        KW_LOG(("Freeing leaked FlsAlloc index %#x\n", pLocalStorage->idx));
-        FlsFree(pLocalStorage->idx);
-        kHlpFree(pLocalStorage);
-        pLocalStorage = pNext;
-    }
+        PKWVIRTALLOC pNext = pTracker->pNext;
+        KW_LOG(("Freeing VirtualFree leak %p LB %#x\n", pTracker->pvAlloc, pTracker->cbAlloc));
 
-    /* Free left behind TlsAlloc leaks. */
-    pLocalStorage = g_Sandbox.pTlsAllocHead;
-    g_Sandbox.pTlsAllocHead = NULL;
-    while (pLocalStorage)
-    {
-        PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
-        KW_LOG(("Freeing leaked TlsAlloc index %#x\n", pLocalStorage->idx));
-        TlsFree(pLocalStorage->idx);
-        kHlpFree(pLocalStorage);
-        pLocalStorage = pNext;
+#ifdef WITH_FIXED_VIRTUAL_ALLOCS
+        if (pTracker->idxPreAllocated != KU32_MAX)
+            kwSandboxResetFixedAllocation(pTracker->idxPreAllocated);
+        else
+#endif
+            VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE);
+        kHlpFree(pTracker);
+        pTracker = pNext;
     }
 
-
     /* Free the environment. */
     if (pSandbox->papszEnvVars)
     {
@@ -7617,62 +9547,110 @@ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
     MemInfo.WorkingSetSize = 0;
     if (GetProcessMemoryInfo(GetCurrentProcess(), &MemInfo, sizeof(MemInfo)))
     {
+        /* The first time thru, we figure out approximately when to restart
+           based on installed RAM and CPU threads. */
+        static KU64 s_cbMaxWorkingSet = 0;
+        if (s_cbMaxWorkingSet != 0)
+        { /* likely */ }
+        else
+        {
+            SYSTEM_INFO SysInfo;
+            MEMORYSTATUSEX GlobalMemInfo;
+            const char    *pszValue;
+
+            /* Calculate a reasonable estimate. */
+            kHlpMemSet(&SysInfo, 0, sizeof(SysInfo));
+            GetNativeSystemInfo(&SysInfo);
+
+            kHlpMemSet(&GlobalMemInfo, 0, sizeof(GlobalMemInfo));
+            GlobalMemInfo.dwLength = sizeof(GlobalMemInfo);
+            if (!GlobalMemoryStatusEx(&GlobalMemInfo))
 #if K_ARCH_BITS >= 64
-        if (MemInfo.WorkingSetSize >= 512*1024*1024)
+                GlobalMemInfo.ullTotalPhys = KU64_C(0x000200000000); /* 8GB */
 #else
-        if (MemInfo.WorkingSetSize >= 384*1024*1024)
+                GlobalMemInfo.ullTotalPhys = KU64_C(0x000080000000); /* 2GB */
+#endif
+            s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys / (K_MAX(SysInfo.dwNumberOfProcessors, 1) * 4);
+            KW_LOG(("Raw estimate of s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet));
+
+            /* User limit. */
+            pszValue = getenv("KWORKER_MEMORY_LIMIT");
+            if (pszValue != NULL)
+            {
+                char         *pszNext;
+                unsigned long ulValue = strtol(pszValue, &pszNext, 0);
+                if (*pszNext == '\0' || *pszNext == 'M')
+                    s_cbMaxWorkingSet = ulValue * (KU64)1048576;
+                else if (*pszNext == 'K')
+                    s_cbMaxWorkingSet = ulValue * (KU64)1024;
+                else if (*pszNext == 'G')
+                    s_cbMaxWorkingSet = ulValue * (KU64)1073741824;
+                else
+                    kwErrPrintf("Unable to grok KWORKER_MEMORY_LIMIT: %s\n", pszValue);
+                KW_LOG(("User s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet));
+            }
+
+            /* Clamp it a little. */
+            if (s_cbMaxWorkingSet < 168*1024*1024)
+                s_cbMaxWorkingSet = 168*1024*1024;
+#if K_ARCH_BITS < 64
+            else
+                s_cbMaxWorkingSet = K_MIN(s_cbMaxWorkingSet,
+                                          SysInfo.dwProcessorType != PROCESSOR_ARCHITECTURE_AMD64
+                                          ?  512*1024*1024 /* Only got 2 or 3 GB VA */
+                                          : 1536*1024*1024 /* got 4GB VA */);
 #endif
+            if (s_cbMaxWorkingSet > GlobalMemInfo.ullTotalPhys)
+                s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys;
+            KW_LOG(("Final s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet));
+        }
+
+        /* Finally the check. */
+        if (MemInfo.WorkingSetSize >= s_cbMaxWorkingSet)
         {
             KW_LOG(("WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize));
-            //fprintf(stderr, "WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize);
             g_fRestart = K_TRUE;
         }
     }
+
+    /*
+     * The CRT has a max of 8192 handles, so we better restart after a while if
+     * someone is leaking handles or we risk running out of descriptors.
+     *
+     * Note! We only detect leaks for handles we intercept.  In the case of CL.EXE
+     *       doing _dup2(1, 2) (stderr ==> stdout), there isn't actually a leak.
+     */
+    if (pSandbox->cLeakedHandles > 6000)
+    {
+        KW_LOG(("LeakedHandles = %#x - > restart next time.\n", pSandbox->cLeakedHandles));
+        g_fRestart = K_TRUE;
+    }
 }
 
 
+/**
+ * Does essential cleanups and restoring, anything externally visible.
+ *
+ * All cleanups that aren't externally visible are postponed till after we've
+ * informed kmk of the result, so it can be done in the dead time between jobs.
+ *
+ * @param   pSandbox            The sandbox.
+ */
 static void kwSandboxCleanup(PKWSANDBOX pSandbox)
 {
     /*
      * Restore the parent command line string.
      */
     PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
-    pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
-
-    /*
-     * Kill all open handles.
-     */
-    if (pSandbox->cActiveHandles > 0)
-    {
-        KU32 i = pSandbox->cHandles;
-        while (i-- > 0)
-            if (pSandbox->papHandles[i] == NULL)
-            { /* likely */ }
-            else
-            {
-                PKWHANDLE pHandle = pSandbox->papHandles[i];
-                pSandbox->papHandles[i] = NULL;
-                switch (pHandle->enmType)
-                {
-                    case KWHANDLETYPE_FSOBJ_READ_CACHE:
-                        break;
-                    case KWHANDLETYPE_TEMP_FILE:
-                    case KWHANDLETYPE_TEMP_FILE_MAPPING:
-                        pHandle->u.pTempFile->cActiveHandles--;
-                        break;
-                    default:
-                        kHlpAssertFailed();
-                }
-                kHlpFree(pHandle);
-                if (--pSandbox->cActiveHandles == 0)
-                    break;
-            }
-    }
+    PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
+    pProcParams->CommandLine    = pSandbox->SavedCommandLine;
+    pProcParams->StandardOutput = pSandbox->StdOut.hOutput;
+    pProcParams->StandardError  = pSandbox->StdErr.hOutput; /* CL.EXE messes with this one. */
 }
 
 
 static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
-                         KU32 cEnvVars, const char **papszEnvVars)
+                         KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching)
 {
     int rcExit = 42;
     int rc;
@@ -7680,7 +9658,7 @@ static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const c
     /*
      * Initialize the sandbox environment.
      */
-    rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
+    rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching);
     if (rc == 0)
     {
         /*
@@ -7741,6 +9719,18 @@ static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const c
 #endif
             __except (EXCEPTION_EXECUTE_HANDLER)
             {
+                kwErrPrintf("Caught exception %#x!\n", GetExceptionCode());
+#ifdef WITH_HISTORY
+                {
+                    KU32 cPrinted = 0;
+                    while (cPrinted++ < 5)
+                    {
+                        KU32 idx = (g_iHistoryNext + K_ELEMENTS(g_apszHistory) - cPrinted) % K_ELEMENTS(g_apszHistory);
+                        if (g_apszHistory[idx])
+                            kwErrPrintf("cmd[%d]: %s\n", 1 - cPrinted, g_apszHistory[idx]);
+                    }
+                }
+#endif
                 rcExit = 512;
             }
             pSandbox->fRunning = K_FALSE;
@@ -7801,18 +9791,33 @@ static int kSubmitHandleJobPostCmd(KU32 cPostCmdArgs, const char **papszPostCmdA
  * @param   papszArgs           The argument vector.
  * @param   fWatcomBrainDamange Whether to apply watcom rules while quoting.
  * @param   cEnvVars            The number of environment variables.
- * @param   papszEnvVars        The enviornment vector.
+ * @param   papszEnvVars        The environment vector.
+ * @param   fNoPchCaching       Whether to disable precompiled header file
+ *                              caching.  Avoid trouble when creating them.
  * @param   cPostCmdArgs        Number of post command arguments (includes cmd).
  * @param   papszPostCmdArgs    The post command and its argument.
  */
 static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
                                     KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
-                                    KU32 cEnvVars, const char **papszEnvVars,
+                                    KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching,
                                     KU32 cPostCmdArgs, const char **papszPostCmdArgs)
 {
     int rcExit;
     PKWTOOL pTool;
 
+    KW_LOG(("\n\nkSubmitHandleJobUnpacked: '%s' in '%s' cArgs=%u cEnvVars=%u cPostCmdArgs=%u\n",
+            pszExecutable, pszCwd, cArgs, cEnvVars, cPostCmdArgs));
+#ifdef KW_LOG_ENABLED
+    {
+        KU32 i;
+        for (i = 0; i < cArgs; i++)
+            KW_LOG(("  papszArgs[%u]=%s\n", i, papszArgs[i]));
+        for (i = 0; i < cPostCmdArgs; i++)
+            KW_LOG(("  papszPostCmdArgs[%u]=%s\n", i, papszPostCmdArgs[i]));
+    }
+#endif
+    g_cJobs++;
+
     /*
      * Lookup the tool.
      */
@@ -7851,7 +9856,8 @@ static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCw
                 if (pTool->enmType == KWTOOLTYPE_SANDBOXED)
                 {
                     KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
-                    rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
+                    rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange,
+                                           cEnvVars, papszEnvVars, fNoPchCaching);
                 }
                 else
                 {
@@ -7985,11 +9991,12 @@ static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg)
                                 }
                                 papszEnvVars[cEnvVars] = 0;
 
-                                /* Flags (currently just watcom argument brain damanage). */
-                                if (cbMsg >= sizeof(KU8))
+                                /* Flags (currently just watcom argument brain damage and no precompiled header caching). */
+                                if (cbMsg >= sizeof(KU8) * 2)
                                 {
                                     KBOOL fWatcomBrainDamange = *pszMsg++;
-                                    cbMsg--;
+                                    KBOOL fNoPchCaching = *pszMsg++;
+                                    cbMsg -= 2;
 
                                     /* Post command argument count (can be zero). */
                                     if (cbMsg >= sizeof(KU32))
@@ -8025,7 +10032,7 @@ static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg)
                                                  */
                                                 rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
                                                                                   cArgs, papszArgs, fWatcomBrainDamange,
-                                                                                  cEnvVars, papszEnvVars,
+                                                                                  cEnvVars, papszEnvVars, fNoPchCaching,
                                                                                   cPostCmdArgs, apszPostCmdArgs);
                                             }
                                             else if (cbMsg == KSIZE_MAX)
@@ -8150,6 +10157,176 @@ static int kSubmitReadIt(HANDLE hPipe, void *pvBuf, KU32 cbToRead, KBOOL fMayShu
 
 
 /**
+ * Decimal formatting of a 64-bit unsigned value into a large enough buffer.
+ *
+ * @returns pszBuf
+ * @param   pszBuf              The buffer (sufficiently large).
+ * @param   uValue              The value.
+ */
+static const char *kwFmtU64(char *pszBuf, KU64 uValue)
+{
+    char  szTmp[64];
+    char *psz = &szTmp[63];
+    int   cch = 4;
+
+    *psz-- = '\0';
+    do
+    {
+        if (--cch == 0)
+        {
+            *psz-- = ' ';
+            cch = 3;
+        }
+        *psz-- = (uValue % 10) + '0';
+        uValue /= 10;
+    } while (uValue != 0);
+
+    return strcpy(pszBuf, psz + 1);
+}
+
+
+/**
+ * Prints statistics.
+ */
+static void kwPrintStats(void)
+{
+    PROCESS_MEMORY_COUNTERS_EX MemInfo;
+    MEMORYSTATUSEX MemStatus;
+    IO_COUNTERS IoCounters;
+    DWORD cHandles;
+    KSIZE cMisses;
+    char  szBuf[16*1024];
+    int   off = 0;
+    char  szPrf[24];
+    char  sz1[64];
+    char  sz2[64];
+    char  sz3[64];
+    char  sz4[64];
+    extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile);
+
+    sprintf(szPrf, "%5d/%u:", getpid(), K_ARCH_BITS);
+
+    szBuf[off++] = '\n';
+
+    off += sprintf(&szBuf[off], "%s %14s jobs, %s tools, %s modules, %s non-native ones\n", szPrf,
+                   kwFmtU64(sz1, g_cJobs), kwFmtU64(sz2, g_cTools), kwFmtU64(sz3, g_cModules), kwFmtU64(sz4, g_cNonNativeModules));
+    off += sprintf(&szBuf[off], "%s %14s bytes in %s read-cached files, avg %s bytes\n", szPrf,
+                   kwFmtU64(sz1, g_cbReadCachedFiles), kwFmtU64(sz2, g_cReadCachedFiles),
+                   kwFmtU64(sz3, g_cbReadCachedFiles / K_MAX(g_cReadCachedFiles, 1)));
+
+    off += sprintf(&szBuf[off], "%s %14s bytes read in %s calls\n",
+                   szPrf, kwFmtU64(sz1, g_cbReadFileTotal), kwFmtU64(sz2, g_cReadFileCalls));
+
+    off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from read cached files\n", szPrf,
+                   kwFmtU64(sz1, g_cbReadFileFromReadCached), (unsigned)(g_cbReadFileFromReadCached * (KU64)100 / g_cbReadFileTotal),
+                   kwFmtU64(sz2, g_cReadFileFromReadCached), (unsigned)(g_cReadFileFromReadCached * (KU64)100 / g_cReadFileCalls));
+
+    off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from in-memory temporary files\n", szPrf,
+                   kwFmtU64(sz1, g_cbReadFileFromInMemTemp), (unsigned)(g_cbReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cbReadFileTotal, 1)),
+                   kwFmtU64(sz2, g_cReadFileFromInMemTemp), (unsigned)(g_cReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cReadFileCalls, 1)));
+
+    off += sprintf(&szBuf[off], "%s %14s bytes written in %s calls\n", szPrf,
+                   kwFmtU64(sz1, g_cbWriteFileTotal), kwFmtU64(sz2, g_cWriteFileCalls));
+    off += sprintf(&szBuf[off], "%s %14s bytes written (%u%%) in %s calls (%u%%) to in-memory temporary files\n", szPrf,
+                   kwFmtU64(sz1, g_cbWriteFileToInMemTemp),
+                   (unsigned)(g_cbWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cbWriteFileTotal, 1)),
+                   kwFmtU64(sz2, g_cWriteFileToInMemTemp),
+                   (unsigned)(g_cWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cWriteFileCalls, 1)));
+
+    off += sprintf(&szBuf[off], "%s %14s bytes for the cache\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cbObjects + g_pFsCache->cbAnsiPaths + g_pFsCache->cbUtf16Paths + sizeof(*g_pFsCache)));
+    off += sprintf(&szBuf[off], "%s %14s objects, taking up %s bytes, avg %s bytes\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cObjects),
+                   kwFmtU64(sz2, g_pFsCache->cbObjects),
+                   kwFmtU64(sz3, g_pFsCache->cbObjects / g_pFsCache->cObjects));
+    off += sprintf(&szBuf[off], "%s %14s A path hashes, taking up %s bytes, avg %s bytes, %s collision\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cAnsiPaths),
+                   kwFmtU64(sz2, g_pFsCache->cbAnsiPaths),
+                   kwFmtU64(sz3, g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1)),
+                   kwFmtU64(sz4, g_pFsCache->cAnsiPathCollisions));
+#ifdef KFSCACHE_CFG_UTF16
+    off += sprintf(&szBuf[off], "%s %14s W path hashes, taking up %s bytes, avg %s bytes, %s collisions\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cUtf16Paths),
+                   kwFmtU64(sz2, g_pFsCache->cbUtf16Paths),
+                   kwFmtU64(sz3, g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1)),
+                   kwFmtU64(sz4, g_pFsCache->cUtf16PathCollisions));
+#endif
+    off += sprintf(&szBuf[off], "%s %14s child hash tables, total of %s entries, %s children inserted, %s collisions\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cChildHashTabs),
+                   kwFmtU64(sz2, g_pFsCache->cChildHashEntriesTotal),
+                   kwFmtU64(sz3, g_pFsCache->cChildHashed),
+                   kwFmtU64(sz4, g_pFsCache->cChildHashCollisions));
+
+    cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits;
+    off += sprintf(&szBuf[off], "%s %14s lookups: %s (%u%%) path hash hits, %s (%u%%) walks hits, %s (%u%%) misses\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cLookups),
+                   kwFmtU64(sz2, g_pFsCache->cPathHashHits),
+                   (unsigned)(g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)),
+                   kwFmtU64(sz3, g_pFsCache->cWalkHits),
+                   (unsigned)(g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)),
+                   kwFmtU64(sz4, cMisses),
+                   (unsigned)(cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)));
+
+    off += sprintf(&szBuf[off], "%s %14s child searches, %s (%u%%) hash hits\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cChildSearches),
+                   kwFmtU64(sz2, g_pFsCache->cChildHashHits),
+                   (unsigned)(g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1)));
+    off += sprintf(&szBuf[off], "%s %14s name changes, growing %s times (%u%%)\n", szPrf,
+                   kwFmtU64(sz1, g_pFsCache->cNameChanges),
+                   kwFmtU64(sz2, g_pFsCache->cNameGrowths),
+                   (unsigned)(g_pFsCache->cNameGrowths * 100 / K_MAX(g_pFsCache->cNameChanges, 1)) );
+
+
+    /*
+     * Process & Memory details.
+     */
+    if (!GetProcessHandleCount(GetCurrentProcess(), &cHandles))
+        cHandles = 0;
+    MemInfo.cb = sizeof(MemInfo);
+    if (!GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&MemInfo, sizeof(MemInfo)))
+        memset(&MemInfo, 0, sizeof(MemInfo));
+    off += sprintf(&szBuf[off], "%s %14s handles; %s page faults; %s bytes page file, peaking at %s bytes\n", szPrf,
+                   kwFmtU64(sz1, cHandles),
+                   kwFmtU64(sz2, MemInfo.PageFaultCount),
+                   kwFmtU64(sz3, MemInfo.PagefileUsage),
+                   kwFmtU64(sz4, MemInfo.PeakPagefileUsage));
+    off += sprintf(&szBuf[off], "%s %14s bytes working set, peaking at %s bytes; %s byte private\n", szPrf,
+                   kwFmtU64(sz1, MemInfo.WorkingSetSize),
+                   kwFmtU64(sz2, MemInfo.PeakWorkingSetSize),
+                   kwFmtU64(sz3, MemInfo.PrivateUsage));
+    off += sprintf(&szBuf[off], "%s %14s bytes non-paged pool, peaking at %s bytes; %s bytes paged pool, peaking at %s bytes\n",
+                   szPrf,
+                   kwFmtU64(sz1, MemInfo.QuotaNonPagedPoolUsage),
+                   kwFmtU64(sz2, MemInfo.QuotaPeakNonPagedPoolUsage),
+                   kwFmtU64(sz3, MemInfo.QuotaPagedPoolUsage),
+                   kwFmtU64(sz4, MemInfo.QuotaPeakPagedPoolUsage));
+
+    if (!GetProcessIoCounters(GetCurrentProcess(), &IoCounters))
+        memset(&IoCounters, 0, sizeof(IoCounters));
+    off += sprintf(&szBuf[off], "%s %14s bytes in %s reads [src: OS]\n", szPrf,
+                   kwFmtU64(sz1, IoCounters.ReadTransferCount),
+                   kwFmtU64(sz2, IoCounters.ReadOperationCount));
+    off += sprintf(&szBuf[off], "%s %14s bytes in %s writes [src: OS]\n", szPrf,
+                   kwFmtU64(sz1, IoCounters.WriteTransferCount),
+                   kwFmtU64(sz2, IoCounters.WriteOperationCount));
+    off += sprintf(&szBuf[off], "%s %14s bytes in %s other I/O operations [src: OS]\n", szPrf,
+                   kwFmtU64(sz1, IoCounters.OtherTransferCount),
+                   kwFmtU64(sz2, IoCounters.OtherOperationCount));
+
+    MemStatus.dwLength = sizeof(MemStatus);
+    if (!GlobalMemoryStatusEx(&MemStatus))
+        memset(&MemStatus, 0, sizeof(MemStatus));
+    off += sprintf(&szBuf[off], "%s %14s bytes used VA, %#" KX64_PRI " bytes available\n", szPrf,
+                   kwFmtU64(sz1, MemStatus.ullTotalVirtual - MemStatus.ullAvailVirtual),
+                   MemStatus.ullAvailVirtual);
+    off += sprintf(&szBuf[off], "%s %14u %% system memory load\n", szPrf, MemStatus.dwMemoryLoad);
+
+    maybe_con_fwrite(szBuf, off, 1, stdout);
+    fflush(stdout);
+}
+
+
+/**
  * Handles what comes after --test.
  *
  * @returns Exit code.
@@ -8166,6 +10343,7 @@ static int kwTestRun(int argc, char **argv)
     const char *pszCwd = getcwd(szCwd, sizeof(szCwd));
     KU32        cEnvVars;
     KBOOL       fWatcomBrainDamange = K_FALSE;
+    KBOOL       fNoPchCaching = K_FALSE;
 
     /*
      * Parse arguments.
@@ -8183,7 +10361,8 @@ static int kwTestRun(int argc, char **argv)
 
         /* Optional directory change. */
         if (   i < argc
-            && strcmp(argv[i], "--chdir") == 0)
+            && (   strcmp(argv[i], "--chdir") == 0
+                || strcmp(argv[i], "-C")      == 0 ) )
         {
             i++;
             if (i >= argc)
@@ -8200,6 +10379,22 @@ static int kwTestRun(int argc, char **argv)
             i++;
         }
 
+        /* Optional watcom flag directory change. */
+        if (   i < argc
+            && strcmp(argv[i], "--no-pch-caching") == 0)
+        {
+            fNoPchCaching = K_TRUE;
+            i++;
+        }
+
+        /* Trigger breakpoint */
+        if (   i < argc
+            && strcmp(argv[i], "--breakpoint") == 0)
+        {
+            __debugbreak();
+            i++;
+        }
+
         /* Check for '--'. */
         if (i >= argc)
             return kwErrPrintfRc(2, "Missing '--'\n");
@@ -8226,32 +10421,65 @@ static int kwTestRun(int argc, char **argv)
     {
         rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd,
                                           argc - i, &argv[i], fWatcomBrainDamange,
-                                          cEnvVars, environ,
+                                          cEnvVars, environ, fNoPchCaching,
                                           0, NULL);
         KW_LOG(("rcExit=%d\n", rcExit));
         kwSandboxCleanupLate(&g_Sandbox);
     }
 
+    if (getenv("KWORKER_STATS") != NULL)
+        kwPrintStats();
+
+# ifdef WITH_LOG_FILE
+    if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
+        CloseHandle(g_hLogFile);
+# endif
     return rcExit;
 }
 
-#if 1
 
 int main(int argc, char **argv)
 {
-    KSIZE           cbMsgBuf = 0;
-    KU8            *pbMsgBuf = NULL;
-    int             i;
-    HANDLE          hPipe = INVALID_HANDLE_VALUE;
-    const char     *pszTmp;
-    KFSLOOKUPERROR  enmIgnored;
+    KSIZE                           cbMsgBuf = 0;
+    KU8                            *pbMsgBuf = NULL;
+    int                             i;
+    HANDLE                          hPipe = INVALID_HANDLE_VALUE;
+    const char                     *pszTmp;
+    KFSLOOKUPERROR                  enmIgnored;
 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
-    PVOID           pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained);
+    PVOID                           pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/,
+                                                                                   kwSandboxVecXcptEmulateChained);
 #endif
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     HANDLE                          hCurProc       = GetCurrentProcess();
     PPEB                            pPeb           = kwSandboxGetProcessEnvironmentBlock();
     PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
+    DWORD                           dwType;
+#endif
+
+
+#ifdef WITH_FIXED_VIRTUAL_ALLOCS
+    /*
+     * Reserve memory for cl.exe
+     */
+    for (i = 0; i < K_ELEMENTS(g_aFixedVirtualAllocs); i++)
+    {
+        g_aFixedVirtualAllocs[i].fInUse     = K_FALSE;
+        g_aFixedVirtualAllocs[i].pvReserved = VirtualAlloc((void *)g_aFixedVirtualAllocs[i].uFixed,
+                                                           g_aFixedVirtualAllocs[i].cbFixed,
+                                                           MEM_RESERVE, PAGE_READWRITE);
+        if (   !g_aFixedVirtualAllocs[i].pvReserved
+            || g_aFixedVirtualAllocs[i].pvReserved != (void *)g_aFixedVirtualAllocs[i].uFixed)
+        {
+            kwErrPrintf("Failed to reserve %p LB %#x: %u\n", g_aFixedVirtualAllocs[i].uFixed, g_aFixedVirtualAllocs[i].cbFixed,
+                        GetLastError());
+            if (g_aFixedVirtualAllocs[i].pvReserved)
+            {
+                VirtualFree(g_aFixedVirtualAllocs[i].pvReserved, g_aFixedVirtualAllocs[i].cbFixed, MEM_RELEASE);
+                g_aFixedVirtualAllocs[i].pvReserved = NULL;
+            }
+        }
+    }
 #endif
 
     /*
@@ -8277,22 +10505,67 @@ int main(int argc, char **argv)
     if (pszTmp && *pszTmp != '\0')
         kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
 
+    /*
+     * Make g_abDefLdBuf executable.
+     */
+    if (!VirtualProtect(g_abDefLdBuf, sizeof(g_abDefLdBuf), PAGE_EXECUTE_READWRITE, &dwType))
+        return kwErrPrintfRc(3, "VirtualProtect(%p, %#x, PAGE_EXECUTE_READWRITE,NULL) failed: %u\n",
+                             g_abDefLdBuf, sizeof(g_abDefLdBuf), GetLastError());
+
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     /*
      * Get and duplicate the console handles.
      */
+    /* Standard output. */
     g_Sandbox.StdOut.hOutput = pProcessParams->StandardOutput;
     if (!DuplicateHandle(hCurProc, pProcessParams->StandardOutput, hCurProc, &g_Sandbox.StdOut.hBackup,
                          GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
         kHlpAssertFailedStmt(g_Sandbox.StdOut.hBackup = pProcessParams->StandardOutput);
-    g_Sandbox.StdOut.fIsConsole = GetFileType(g_Sandbox.StdOut.hOutput) == FILE_TYPE_CHAR;
+    dwType = GetFileType(g_Sandbox.StdOut.hOutput);
+    g_Sandbox.StdOut.fIsConsole = dwType == FILE_TYPE_CHAR;
+    g_Sandbox.StdOut.fFileType  = (dwType & ~FILE_TYPE_REMOTE) < 0xf
+                                ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX;
+    g_Sandbox.HandleStdOut.enmType         = KWHANDLETYPE_OUTPUT_BUF;
+    g_Sandbox.HandleStdOut.cRefs           = 0x10001;
+    g_Sandbox.HandleStdOut.dwDesiredAccess = GENERIC_WRITE;
+    g_Sandbox.HandleStdOut.u.pOutBuf       = &g_Sandbox.StdOut;
+    g_Sandbox.HandleStdOut.hHandle         = g_Sandbox.StdOut.hOutput;
+    if (g_Sandbox.StdOut.hOutput != INVALID_HANDLE_VALUE)
+    {
+        if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdOut, g_Sandbox.StdOut.hOutput))
+            g_Sandbox.cFixedHandles++;
+        else
+            return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdOut (%p)!\n", g_Sandbox.StdOut.hOutput);
+    }
+    KWOUT_LOG(("StdOut: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n",
+               g_Sandbox.StdOut.hOutput, g_Sandbox.StdOut.hBackup, g_Sandbox.StdOut.fIsConsole, dwType));
 
+    /* Standard error. */
     g_Sandbox.StdErr.hOutput = pProcessParams->StandardError;
     if (!DuplicateHandle(hCurProc, pProcessParams->StandardError, hCurProc, &g_Sandbox.StdErr.hBackup,
                          GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
         kHlpAssertFailedStmt(g_Sandbox.StdErr.hBackup = pProcessParams->StandardError);
-    g_Sandbox.StdErr.fIsConsole = GetFileType(g_Sandbox.StdErr.hOutput) == FILE_TYPE_CHAR;
+    dwType = GetFileType(g_Sandbox.StdErr.hOutput);
+    g_Sandbox.StdErr.fIsConsole = dwType == FILE_TYPE_CHAR;
+    g_Sandbox.StdErr.fFileType  = (dwType & ~FILE_TYPE_REMOTE) < 0xf
+                                ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX;
+    g_Sandbox.HandleStdErr.enmType         = KWHANDLETYPE_OUTPUT_BUF;
+    g_Sandbox.HandleStdErr.cRefs           = 0x10001;
+    g_Sandbox.HandleStdErr.dwDesiredAccess = GENERIC_WRITE;
+    g_Sandbox.HandleStdErr.u.pOutBuf       = &g_Sandbox.StdErr;
+    g_Sandbox.HandleStdErr.hHandle         = g_Sandbox.StdErr.hOutput;
+    if (   g_Sandbox.StdErr.hOutput != INVALID_HANDLE_VALUE
+        && g_Sandbox.StdErr.hOutput != g_Sandbox.StdOut.hOutput)
+    {
+        if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdErr, g_Sandbox.StdErr.hOutput))
+            g_Sandbox.cFixedHandles++;
+        else
+            return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdErr (%p)!\n", g_Sandbox.StdErr.hOutput);
+    }
+    KWOUT_LOG(("StdErr: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n",
+               g_Sandbox.StdErr.hOutput, g_Sandbox.StdErr.hBackup, g_Sandbox.StdErr.fIsConsole, dwType));
 
+    /* Combined console buffer. */
     if (g_Sandbox.StdErr.fIsConsole)
     {
         g_Sandbox.Combined.hOutput   = g_Sandbox.StdErr.hBackup;
@@ -8308,7 +10581,8 @@ int main(int argc, char **argv)
         g_Sandbox.Combined.hOutput   = INVALID_HANDLE_VALUE;
         g_Sandbox.Combined.uCodepage = CP_ACP;
     }
-#endif
+    KWOUT_LOG(("Combined: hOutput=%p uCodepage=%d\n", g_Sandbox.Combined.hOutput, g_Sandbox.Combined.uCodepage));
+#endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
 
 
     /*
@@ -8353,7 +10627,7 @@ int main(int argc, char **argv)
             printf("usage: kWorker [--volatile dir] --pipe <pipe-handle>\n"
                    "usage: kWorker <--help|-h>\n"
                    "usage: kWorker <--version|-V>\n"
-                   "usage: kWorker [--volatile dir] --test [<times> [--chdir <dir>]] -- args\n"
+                   "usage: kWorker [--volatile dir] --test [<times> [--chdir <dir>] [--breakpoint] -- args\n"
                    "\n"
                    "This is an internal kmk program that is used via the builtin_kSubmit.\n");
             return 0;
@@ -8451,75 +10725,228 @@ int main(int argc, char **argv)
         }
 
         CloseHandle(hPipe);
+#ifdef WITH_LOG_FILE
+        if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
+            CloseHandle(g_hLogFile);
+#endif
+        if (getenv("KWORKER_STATS") != NULL)
+            kwPrintStats();
         return rc > 0 ? 0 : 1;
     }
 }
 
-#else
-
-static int kwExecCmdLine(const char *pszExe, const char *pszCmdLine)
-{
-    int rc;
-    PKWTOOL pTool = kwToolLookup(pszExe);
-    if (pTool)
-    {
-        int rcExitCode;
-        switch (pTool->enmType)
-        {
-            case KWTOOLTYPE_SANDBOXED:
-                KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
-                rc = kwSandboxExec(&g_Sandbox, pTool, pszCmdLine, &rcExitCode);
-                break;
-            default:
-                kHlpAssertFailed();
-                KW_LOG(("TODO: Direct exec tool %s\n", pTool->pszPath));
-                rc = rcExitCode = 2;
-                break;
-        }
-        KW_LOG(("rcExitCode=%d (rc=%d)\n", rcExitCode, rc));
-    }
-    else
-        rc = 1;
-    return rc;
-}
-
-int main(int argc, char **argv)
-{
-    int rc = 0;
-    int i;
-    argv[2] = "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v1 [...]
-# if 0
-    rc = kwExecCmdLine(argv[1], argv[2]);
-    rc = kwExecCmdLine(argv[1], argv[2]);
-    K_NOREF(i);
-# else
-// Skylake (W10/amd64, only stdandard MS defender):
-//     cmd 1:  48    /1024 = 0x0 (0.046875)        [for /l %i in (1,1,1024) do ...]
-//     kmk 1:  44    /1024 = 0x0 (0.04296875)      [all: ; 1024 x cl.exe]
-//     run 1:  37    /1024 = 0x0 (0.0361328125)    [just process creation gain]
-//     run 2:  34    /1024 = 0x0 (0.033203125)     [get file attribs]
-//     run 3:  32.77 /1024 = 0x0 (0.032001953125)  [read caching of headers]
-//     run 4:  32.67 /1024 = 0x0 (0.031904296875)  [loader tweaking]
-//     run 5:  29.144/1024 = 0x0 (0.0284609375)    [with temp files in memory]
-//    r2881 building src/VBox/Runtime:
-//     without: 2m01.016388s = 120.016388 s
-//     with:    1m15.165069s = 75.165069 s => 120.016388s - 75.165069s = 44.851319s => 44.85/120.02 = 37% speed up.
-//    r2884 building vbox/debug (r110512):
-//     without: 11m14.446609s = 674.446609 s
-//     with:     9m01.017344s = 541.017344 s => 674.446609s - 541.017344s = 133.429265 => 133.43/674.45 = 19% speed up
-//    r2896 building vbox/debug (r110577):
-//     with:     8m31.182384s = 511.182384 s => 674.446609s - 511.182384s = 163.264225 = 163.26/674.45 = 24% speed up
-//
-// Dell (W7/amd64, infected by mcafee):
-//     kmk 1: 285.278/1024 = 0x0 (0.278591796875)
-//     run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
-//     run 2:  78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
-    g_cVerbose = 0;
-    for (i = 0; i < 1024 && rc == 0; i++)
-        rc = kwExecCmdLine(argv[1], argv[2]);
-# endif
-    return rc;
-}
 
-#endif
+/** @page pg_kWorker    kSubmit / kWorker
+ *
+ * @section sec_kWorker_Motivation  Motivation / Inspiration
+ *
+ * The kSubmit / kWorker combo was conceived as a way to speed up VirtualBox
+ * builds on machines "infested" by Anti Virus protection and disk encryption
+ * software.  Build times jumping from 35-40 min to 77-82 min after the machine
+ * got "infected".
+ *
+ * Speeing up builting of Boot Sector Kit \#3 was also hightly desirable. It is
+ * mainly a bunch of tiny assembly and C files being compiler a million times.
+ * As some of us OS/2 users maybe recalls, the Watcom make program can run its
+ * own toolchain from within the same process, saving a lot of process creation
+ * and teardown overhead.
+ *
+ *
+ * @section sec_kWorker_kSubmit     About kSubmit
+ *
+ * When wanting to execute a job in a kWorker instance, it must be submitted
+ * using the kmk_builtin_kSubmit command in kmk.  As the name suggest, this is
+ * built into kmk and does not exist as an external program.  The reason for
+ * this is that it keep track of the kWorker instances.
+ *
+ * The kSubmit command has the --32-bit and --64-bit options for selecting
+ * between 32-bit and 64-bit worker instance.  We generally assume the user of
+ * the command knows which bit count the executable has, so kSubmit is spared
+ * the extra work of finding out.
+ *
+ * The kSubmit command shares a environment and current directory manipulation
+ * with the kRedirect command, but not the file redirection.  So long no file
+ * operation is involed, kSubmit is a drop in kRedirect replacement.  This is
+ * hand for tools like OpenWatcom, NASM and YASM which all require environment
+ * and/or current directory changes to work.
+ *
+ * Unlike the kRedirect command, the kSubmit command can also specify an
+ * internall post command to be executed after the main command succeeds.
+ * Currently only kmk_builtin_kDepObj is supported.  kDepObj gathers dependency
+ * information from Microsoft COFF object files and Watcom OMF object files and
+ * is scheduled to replace kDepIDB.
+ *
+ *
+ * @section sec_kWorker_Interaction kSubmit / kWorker interaction
+ *
+ * The kmk_builtin_kSubmit communicates with the kWorker instances over pipes.
+ * A job request is written by kSubmit and kWorker read, unpacks it and executes
+ * it.  When the job is completed, kWorker writes a short reply with the exit
+ * code and an internal status indicating whether it is going to restart.
+ *
+ * The kWorker intance will reply to kSubmit before completing all the internal
+ * cleanup work, so as not to delay the next job execution unnecessarily.  This
+ * includes checking its own memory consumption and checking whether it needs
+ * restarting.  So, a decision to restart unfortunately have to wait till after
+ * the next job has completed.  This is a little bit unfortunate if the next job
+ * requires a lot of memory and kWorker has already leaked/used a lot.
+ *
+ *
+ * @section sec_kWorker_How_Works   How kWorker Works
+ *
+ * kWorker will load the executable specified by kSubmit into memory and call
+ * it's entrypoint in a lightly sandbox'ed environment.
+ *
+ *
+ * @subsection ssec_kWorker_Loaing      Image loading
+ *
+ * kWorker will manually load all the executable images into memory, fix them
+ * up, and make a copy of the virgin image so it can be restored using memcpy
+ * the next time it is used.
+ *
+ * Imported functions are monitored and replacements used for a few of them.
+ * These replacements are serve the following purposes:
+ *      - Provide a different command line.
+ *      - Provide a different environment.
+ *      - Intercept process termination.
+ *      - Intercept thread creation (only linker is allowed to create threads).
+ *      - Intercept file reading for caching (header files, ++) as file system
+ *        access is made even slower by anti-virus software.
+ *      - Intercept crypto hash APIs to cache MD5 digests of header files
+ *        (c1.dll / c1xx.dll spends a noticable bit of time doing MD5).
+ *      - Intercept temporary files (%TEMP%/_CL_XXXXXXyy) to keep the entirely
+ *        in memory as writing files grows expensive with encryption and
+ *        anti-virus software active.
+ *      - Intercept some file system queries to use the kFsCache instead of
+ *        going to the kernel and slowly worm thru the AV filter driver.
+ *      - Intercept standard output/error and console writes to aggressivly
+ *        buffer the output.  The MS CRT does not buffer either when it goes to
+ *        the console, resulting in terrible performance and mixing up output
+ *        with other compile jobs.
+ *        This also allows us to filter out the annoying source file announcements
+ *        by cl.exe.
+ *      - Intercept VirtualAlloc and VirtualFree to prevent
+ *        CL.EXE/C1.DLL/C1XX.DLL from leaking some 72MB internal allocat area.
+ *      - Intercept FlsAlloc/FlsFree to make sure the allocations are freed and
+ *        the callbacks run after each job.
+ *      - Intercept HeapCreate/HeapFree to reduce leaks from statically linked
+ *        executables and tools using custom heaps (like the microsoft linker).
+ *        [exectuable images only]
+ *      - Intercept atexit and _onexit registration to be able run them after
+ *        each job instead of crashing as kWorker exits.  This also helps avoid
+ *        some leaks. [executable image only]
+ *
+ * DLLs falls into two categories, system DLLs which we always load using the
+ * native loader, and tool DLLs which can be handled like the executable or
+ * optionally using the native loader.  We maintain a hardcoded white listing of
+ * tool DLLs we trust to load using the native loader.
+ *
+ * Imports of natively loaded DLLs are processed too, but we only replace a
+ * subset of the functions compared to natively loaded excutable and DLL images.
+ *
+ * DLLs are never unloaded and we cache LoadLibrary requests (hash the input).
+ * This is to speed up job execution.
+ *
+ * It was thought that we needed to restore (memcpy) natively loaded tool DLLs
+ * for each job run, but so far this hasn't been necessary.
+ *
+ *
+ * @subsection ssec_kWorker_Optimizing  Optimizing the Compiler
+ *
+ * The Visual Studio 2010 C/C++ compiler does a poor job at processing header
+ * files and uses a whole bunch of temporary files (in %TEMP%) for passing
+ * intermediate representation between the first (c1/c1xx.dll) and second pass
+ * (c2.dll).
+ *
+ * kWorker helps the compiler as best as it can.  Given a little knowledge about
+ * stable and volatile file system areas, it can do a lot of caching that a
+ * normal compiler driver cannot easily do when given a single file.
+ *
+ *
+ * @subsubsection sssec_kWorker_Headers     Cache Headers Files and Searches
+ *
+ * The preprocessor part will open and process header files exactly as they are
+ * encountered in the source files.  If string.h is included by the main source
+ * and five other header files, it will be searched for (include path), opened,
+ * read, MD5-summed, and pre-processed six times.  The last five times is just a
+ * waste of time because of the guards or \#pragma once.  A smart compiler would
+ * make a little extra effort and realize this.
+ *
+ * kWorker will cache help the preprocessor by remembering places where the
+ * header was not found with help of kFsCache, and cache the file in memory when
+ * found.  The first part is taken care of by intercepting GetFileAttributesW,
+ * and the latter by intercepting CreateFileW, ReadFile and CloseFile.  Once
+ * cached, the file is kept open and the CreateFileW call returns a duplicate of
+ * that handle.  An internal handle table is used by ReadFile and CloseFile to
+ * keep track of intercepted handles (also used for temporary file, temporary
+ * file mappings, console buffering, and standard out/err buffering).
+ *
+ * PS. The header search optimization also comes in handy when cl.exe goes on
+ *     thru the whole PATH looking for c1/c1xx.exe and c2.exe after finding
+ *     c1/c1xx.dll and c2.dll.  My guess is that the compiler team can
+ *     optionally compile the three pass DLLs as executables during development
+ *     and problem analysis.
+ *
+ *
+ * @subsubsection sssec_kWorker_Temp_Files  Temporary Files In Memory
+ *
+ * The issues of the temporary files is pretty severe on the Dell machine used
+ * for benchmarking with full AV and encryption.  The synthetic benchmark
+ * improved by 30% when kWorker implemented measures to keep them entirely in
+ * memory.
+ *
+ * kWorker implement these by recognizing the filename pattern in CreateFileW
+ * and creating/opening the given file as needed.  The handle returned is a
+ * duplicate of the current process, thus giving us a good chance of catching
+ * API calls we're not intercepting.
+ *
+ * In addition to CreateFileW, we also need to intercept GetFileType, ReadFile,
+ * WriteFile, SetFilePointer+Ex, SetEndOfFile, and CloseFile.  The 2nd pass
+ * additionally requires GetFileSize+Ex, CreateFileMappingW, MapViewOfFile and
+ * UnmapViewOfFile.
+ *
+ *
+ * @section sec_kWorker_Numbers     Some measurements.
+ *
+ *  - r2881 building src/VBox/Runtime:
+ *     - without: 2m01.016388s = 120.016388 s
+ *     - with:    1m15.165069s = 75.165069 s => 120.016388s - 75.165069s = 44.851319s => 44.85/120.02 = 37% speed up.
+ *  - r2884 building vbox/debug (r110512):
+ *     - without: 11m14.446609s = 674.446609 s
+ *     - with:     9m01.017344s = 541.017344 s => 674.446609s - 541.017344s = 133.429265 => 133.43/674.45 = 19% speed up
+ *  - r2896 building vbox/debug (r110577):
+ *     - with:     8m31.182384s = 511.182384 s => 674.446609s - 511.182384s = 163.264225 = 163.26/674.45 = 24% speed up
+ *  - r2920 building vbox/debug (r110702) on Skylake (W10/amd64, only standard
+ *     MS Defender as AV):
+ *     - without: 10m24.990389s = 624.990389s
+ *     - with:    08m04.738184s = 484.738184s
+ *          - delta: 624.99s - 484.74s = 140.25s
+ *          - saved: 140.25/624.99 = 22% faster
+ *
+ *
+ * @subsection subsec_kWorker_Early_Numbers     Early Experiments
+ *
+ * These are some early experiments doing 1024 compilations of
+ * VBoxBS2Linker.cpp using a hard coded command line and looping in kWorker's
+ * main function:
+ *
+ * Skylake (W10/amd64, only stdandard MS defender):
+ *  - cmd 1:  48    /1024 = 0x0 (0.046875)        [for /l %i in (1,1,1024) do ...]
+ *  - kmk 1:  44    /1024 = 0x0 (0.04296875)      [all: ; 1024 x cl.exe]
+ *  - run 1:  37    /1024 = 0x0 (0.0361328125)    [just process creation gain]
+ *  - run 2:  34    /1024 = 0x0 (0.033203125)     [get file attribs]
+ *  - run 3:  32.77 /1024 = 0x0 (0.032001953125)  [read caching of headers]
+ *  - run 4:  32.67 /1024 = 0x0 (0.031904296875)  [loader tweaking]
+ *  - run 5:  29.144/1024 = 0x0 (0.0284609375)    [with temp files in memory]
+ *
+ * Dell (W7/amd64, infected by mcafee):
+ *  - kmk 1: 285.278/1024 = 0x0 (0.278591796875)
+ *  - run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
+ *  - run 2:  78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
+ *
+ * The command line:
+ * @code{.cpp}
+   "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc [...]
+ * @endcode
+ */
 
diff --git a/src/kmk/Makefile.kmk b/src/kmk/Makefile.kmk
index 11fe58f..25a9da6 100644
--- a/src/kmk/Makefile.kmk
+++ b/src/kmk/Makefile.kmk
@@ -1,4 +1,4 @@
-# $Id: Makefile.kmk 2907 2016-09-09 22:33:26Z bird $
+# $Id: Makefile.kmk 2994 2016-11-01 22:41:41Z bird $
 ## @file
 # Sub-makefile for kmk / GNU Make.
 #
@@ -88,6 +88,7 @@ kmkmissing_SOURCES = \
 	kmkbuiltin/setmode.c \
 	kmkbuiltin/strmode.c \
 	kmkbuiltin/kbuild_protection.c \
+	kmkbuiltin/common-env-and-cwd-opt.c \
 	getopt.c \
 	getopt1.c \
 	electric.c
@@ -279,6 +280,7 @@ kmk_SOURCES += \
 	kmkbuiltin/mv.c \
 	kmkbuiltin/ln.c \
 	kmkbuiltin/printf.c \
+	kmkbuiltin/redirect.c \
 	kmkbuiltin/rm.c \
 	kmkbuiltin/rmdir.c \
 	$(if-expr $(KBUILD_TARGET) == win,kmkbuiltin/kSubmit.c) \
@@ -394,7 +396,6 @@ kmk_rm_SOURCES = \
 	kmkbuiltin/rm.c
 
 kmk_redirect_TEMPLATE = BIN-KMK
-kmk_redirect_DEFS = kmk_builtin_redirect=main
 kmk_redirect_SOURCES = \
 	kmkbuiltin/redirect.c
 kmk_redirect_SOURCES.win = \
@@ -530,6 +531,16 @@ PROGRAMS.win += tstFileInfo
 tstFileInfo_TEMPLATE = BIN
 tstFileInfo_SOURCES = w32/tstFileInfo.c
 
+#
+# tstFileInfo
+#
+PROGRAMS.win += tstFtsFake
+tstFtsFake_TEMPLATE = BIN-KMK
+tstFtsFake_NOINST = 1
+tstFtsFake_DEFS = USE_OLD_FTS
+tstFtsFake_SOURCES = ../lib/nt/tstNtFts.c
+
+
 
 include $(FILE_KBUILD_SUB_FOOTER)
 
@@ -545,8 +556,13 @@ $(kmk_0_OUTDIR)/config.h: $(kmk_config.h.$(KBUILD_TARGET))
 #
 # Some missing headers.
 #
+if1of ($(KBUILD_TARGET), win nt)
+$(kmk_0_OUTDIR)/fts.h: $(MAKEFILE) | $(call DIRDEP,$(kmk_0_OUTDIR))
+	$(APPEND) -t "$@" "#include <nt/fts-nt.h>"
+else
 $(kmk_0_OUTDIR)/fts.h: $(kmk_DEFPATH)/kmkbuiltin/ftsfake.h | $(call DIRDEP,$(kmk_0_OUTDIR))
 	$(CP) $^ $@
+endif
 
 $(kmk_0_OUTDIR)/unistd.h: | $(call DIRDEP,$(kmk_0_OUTDIR))
 	$(ECHO_EXT) > $@
diff --git a/src/kmk/dir-nt-bird.c b/src/kmk/dir-nt-bird.c
index cd8ad6d..3724833 100644
--- a/src/kmk/dir-nt-bird.c
+++ b/src/kmk/dir-nt-bird.c
@@ -1,4 +1,4 @@
-/* $Id: dir-nt-bird.c 2886 2016-09-06 14:31:46Z bird $ */
+/* $Id: dir-nt-bird.c 2948 2016-09-20 15:36:07Z bird $ */
 /** @file
  * Reimplementation of dir.c for NT using kFsCache.
  *
@@ -120,8 +120,8 @@ int dir_file_exists_p(const char *pszDir, const char *pszName)
                     fRc = 1;
                 else
                 {
-                    PKFSOBJ pNameObj = kFsCacheLookupRelativeToDirA(g_pFsCache, (PKFSDIR)pDirObj,
-                                                                    pszName, strlen(pszName), &enmError, NULL);
+                    PKFSOBJ pNameObj = kFsCacheLookupRelativeToDirA(g_pFsCache, (PKFSDIR)pDirObj, pszName, strlen(pszName),
+                                                                    0/*fFlags*/, &enmError, NULL);
                     if (pNameObj)
                     {
                         fRc = pNameObj->bObjType == KFSOBJ_TYPE_MISSING;
@@ -412,13 +412,50 @@ void dir_setup_glob(glob_t *pGlob)
 }
 
 
+/**
+ * Print statitstics.
+ */
+void print_dir_stats(void)
+{
+    FILE *pOut = stdout;
+    KU32 cMisses;
+
+    fputs("\n"
+          "# NT dir cache stats:\n", pOut);
+    fprintf(pOut, "#  %u objects, taking up %u (%#x) bytes, avg %u bytes\n",
+            g_pFsCache->cObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects / g_pFsCache->cObjects);
+    fprintf(pOut, "#  %u A path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collision\n",
+            g_pFsCache->cAnsiPaths, g_pFsCache->cbAnsiPaths, g_pFsCache->cbAnsiPaths,
+            g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1), g_pFsCache->cAnsiPathCollisions);
+#ifdef KFSCACHE_CFG_UTF16
+    fprintf(pOut, "#  %u W path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collisions\n",
+            g_pFsCache->cUtf16Paths, g_pFsCache->cbUtf16Paths, g_pFsCache->cbUtf16Paths,
+            g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1), g_pFsCache->cUtf16PathCollisions);
+#endif
+    fprintf(pOut, "#  %u child hash tables, total of %u entries, %u children inserted, %u collisions\n",
+            g_pFsCache->cChildHashTabs, g_pFsCache->cChildHashEntriesTotal,
+            g_pFsCache->cChildHashed, g_pFsCache->cChildHashCollisions);
+
+    cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits;
+    fprintf(pOut, "#  %u lookups: %u (%" KU64_PRI " %%) path hash hits, %u (%" KU64_PRI "%%) walks hits, %u (%" KU64_PRI "%%) misses\n",
+            g_pFsCache->cLookups,
+            g_pFsCache->cPathHashHits, g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1),
+            g_pFsCache->cWalkHits, g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1),
+            cMisses, cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1));
+    fprintf(pOut, "#  %u child searches, %u (%" KU64_PRI "%%) hash hits\n",
+            g_pFsCache->cChildSearches,
+            g_pFsCache->cChildHashHits, g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1));
+}
+
+
 void print_dir_data_base(void)
 {
     /** @todo. */
-}
 
+}
 
 
+/* duplicated in kWorker.c */
 void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
 {
     KFSLOOKUPERROR  enmError;
@@ -440,7 +477,7 @@ void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
                 {
                     kHlpAssert(off > 1);
                     kHlpAssert(pAncestor != NULL);
-                    kHlpAssert(pAncestor->ObjcchName > 0);
+                    kHlpAssert(pAncestor->Obj.cchName > 0);
                     pszFull[--off] = '/';
                     off -= pAncestor->Obj.cchName;
                     kHlpAssert(pAncestor->Obj.cchParent == off);
@@ -585,3 +622,66 @@ int dir_cache_volatile_dir(const char *pszDir)
     return -1;
 }
 
+/**
+ * Invalidates a deleted directory so the cache can close handles to it.
+ *
+ * Used by kmk_builtin_rm and kmk_builtin_rmdir.
+ *
+ * @returns 0 on success, -1 on failure.
+ * @param   pszDir      The directory to invalidate as deleted.
+ */
+int dir_cache_deleted_directory(const char *pszDir)
+{
+    if (kFsCacheInvalidateDeletedDirectoryA(g_pFsCache, pszDir))
+        return 0;
+    return -1;
+}
+
+
+int kmk_builtin_dircache(int argc, char **argv, char **envp)
+{
+    if (argc >= 2)
+    {
+        const char *pszCmd = argv[1];
+        if (strcmp(pszCmd, "invalidate") == 0)
+        {
+            if (argc == 2)
+            {
+                dir_cache_invalid_all();
+                return 0;
+            }
+            fprintf(stderr, "kmk_builtin_dircache: the 'invalidate' command takes no arguments!\n");
+        }
+        else if (strcmp(pszCmd, "invalidate-missing") == 0)
+        {
+            if (argc == 2)
+            {
+                dir_cache_invalid_missing ();
+                return 0;
+            }
+            fprintf(stderr, "kmk_builtin_dircache: the 'invalidate-missing' command takes no arguments!\n");
+        }
+        else if (strcmp(pszCmd, "volatile") == 0)
+        {
+            int i;
+            for (i = 2; i < argc; i++)
+                dir_cache_volatile_dir(argv[i]);
+            return 0;
+        }
+        else if (strcmp(pszCmd, "deleted") == 0)
+        {
+            int i;
+            for (i = 2; i < argc; i++)
+                dir_cache_deleted_directory(argv[i]);
+            return 0;
+        }
+        else
+            fprintf(stderr, "kmk_builtin_dircache: Invalid command '%s'!\n", pszCmd);
+    }
+    else
+        fprintf(stderr, "kmk_builtin_dircache: No command given!\n");
+
+    K_NOREF(envp);
+    return 2;
+}
+
diff --git a/src/kmk/dir.c b/src/kmk/dir.c
index b0e5215..c9b1b37 100644
--- a/src/kmk/dir.c
+++ b/src/kmk/dir.c
@@ -1329,6 +1329,15 @@ print_dir_data_base (void)
 #endif
 }
 

+#ifdef CONFIG_WITH_PRINT_STATS_SWITCH
+/* Print stats */
+
+void print_dir_stats (void)
+{
+  /** @todo normal dir stats.  */
+}
+#endif
+

 /* Hooks for globbing.  */
 
 #if defined(KMK) && !defined(__OS2__)
diff --git a/src/kmk/function.c b/src/kmk/function.c
index ddaf1a9..2720403 100644
--- a/src/kmk/function.c
+++ b/src/kmk/function.c
@@ -5473,6 +5473,18 @@ func_dircache_ctl (char *o, char **argv UNUSED, const char *funcname UNUSED)
             dir_cache_volatile_dir (dir);
         }
     }
+  else if (strcmp (cmd, "deleted") == 0)
+    {
+      size_t i;
+      for (i = 1; argv[i] != NULL; i++)
+        {
+          const char *dir = argv[i];
+          while (isblank ((unsigned char)*dir))
+            dir++;
+          if (*dir)
+            dir_cache_deleted_directory (dir);
+        }
+    }
   else
     error (reading_file, "Unknown $(dircache-ctl ) command: '%s'", cmd);
 # endif
diff --git a/src/kmk/kmkbuiltin.c b/src/kmk/kmkbuiltin.c
index 358f3fc..3cca960 100644
--- a/src/kmk/kmkbuiltin.c
+++ b/src/kmk/kmkbuiltin.c
@@ -1,4 +1,4 @@
-/* $Id: kmkbuiltin.c 2843 2016-08-28 15:31:02Z bird $ */
+/* $Id: kmkbuiltin.c 2912 2016-09-14 13:36:15Z bird $ */
 /** @file
  * kMk Builtin command execution.
  */
@@ -205,8 +205,8 @@ int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char
         rc = kmk_builtin_mkdir(argc, argv, environ);
     else if (!strcmp(pszCmd, "mv"))
         rc = kmk_builtin_mv(argc, argv, environ);
-    /*else if (!strcmp(pszCmd, "redirect"))
-        rc = kmk_builtin_redirect(argc, argv, environ, pPidSpawned);*/
+    else if (!strcmp(pszCmd, "redirect"))
+        rc = kmk_builtin_redirect(argc, argv, environ, pChild, pPidSpawned);
     else if (!strcmp(pszCmd, "rm"))
         rc = kmk_builtin_rm(argc, argv, environ);
     else if (!strcmp(pszCmd, "rmdir"))
@@ -232,6 +232,12 @@ int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char
         rc = kmk_builtin_cat(argc, argv, environ);
     else if (!strcmp(pszCmd, "sleep"))
         rc = kmk_builtin_sleep(argc, argv, environ);
+    else if (!strcmp(pszCmd, "dircache"))
+#ifdef KBUILD_OS_WINDOWS
+        rc = kmk_builtin_dircache(argc, argv, environ);
+#else
+        rc = 0;
+#endif
     else
     {
         printf("kmk_builtin: Unknown command '%s'!\n", pszCmd);
diff --git a/src/kmk/kmkbuiltin.h b/src/kmk/kmkbuiltin.h
index 8c3a8a3..03d0a98 100644
--- a/src/kmk/kmkbuiltin.h
+++ b/src/kmk/kmkbuiltin.h
@@ -1,4 +1,4 @@
-/* $Id: kmkbuiltin.h 2899 2016-09-09 09:03:57Z bird $ */
+/* $Id: kmkbuiltin.h 2912 2016-09-14 13:36:15Z bird $ */
 /** @file
  * kMk Builtin command handling.
  */
@@ -45,6 +45,7 @@ extern int kmk_builtin_cp(int argc, char **argv, char **envp);
 extern int kmk_builtin_cat(int argc, char **argv, char **envp);
 extern int kmk_builtin_chmod(int argc, char **argv, char **envp);
 extern int kmk_builtin_cmp(int argc, char **argv, char **envp);
+extern int kmk_builtin_dircache(int argc, char **argv, char **envp);
 extern int kmk_builtin_echo(int argc, char **argv, char **envp);
 extern int kmk_builtin_expr(int argc, char **argv, char **envp);
 extern int kmk_builtin_install(int argc, char **argv, char **envp);
@@ -53,6 +54,7 @@ extern int kmk_builtin_md5sum(int argc, char **argv, char **envp);
 extern int kmk_builtin_mkdir(int argc, char **argv, char **envp);
 extern int kmk_builtin_mv(int argc, char **argv, char **envp);
 extern int kmk_builtin_printf(int argc, char **argv, char **envp);
+extern int kmk_builtin_redirect(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned);
 extern int kmk_builtin_rm(int argc, char **argv, char **envp);
 extern int kmk_builtin_rmdir(int argc, char **argv, char **envp);
 extern int kmk_builtin_sleep(int argc, char **argv, char **envp);
@@ -72,5 +74,11 @@ extern int kmk_builtin_kDepObj(int argc, char **argv, char **envp);
 
 extern char *kmk_builtin_func_printf(char *o, char **argv, const char *funcname);
 
+/* common-env-and-cwd-opt.c: */
+extern int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+                             int cVerbosity, const char *pszValue);
+extern int kBuiltinOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove);
+extern int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue);
+
 #endif
 
diff --git a/src/kmk/kmkbuiltin/common-env-and-cwd-opt.c b/src/kmk/kmkbuiltin/common-env-and-cwd-opt.c
new file mode 100644
index 0000000..21b76d5
--- /dev/null
+++ b/src/kmk/kmkbuiltin/common-env-and-cwd-opt.c
@@ -0,0 +1,240 @@
+/* $Id: common-env-and-cwd-opt.c 2912 2016-09-14 13:36:15Z bird $ */
+/** @file
+ * kMk Builtin command - Commmon environment and CWD option handling code.
+ */
+
+/*
+ * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "kmkbuiltin.h"
+#include "err.h"
+
+
+/** The environment variable compare function.
+ * We must use case insensitive compare on windows (Path vs PATH).  */
+#ifdef KBUILD_OS_WINDOWS
+# define KSUBMIT_ENV_NCMP   _strnicmp
+#else
+# define KSUBMIT_ENV_NCMP   strncmp
+#endif
+
+
+/**
+ * Handles the --set var=value option.
+ *
+ * @returns 0 on success, non-zero exit code on error.
+ * @param   papszEnv            The environment vector.
+ * @param   pcEnvVars           Pointer to the variable holding the number of
+ *                              environment variables held by @a papszEnv.
+ * @param   pcAllocatedEnvVars  Pointer to the variable holding max size of the
+ *                              environment vector.
+ * @param   cVerbosity          The verbosity level.
+ * @param   pszValue            The var=value string to apply.
+ */
+int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue)
+{
+    const char *pszEqual = strchr(pszValue, '=');
+    if (pszEqual)
+    {
+        char   **papszEnv = *ppapszEnv;
+        unsigned iEnvVar;
+        unsigned cEnvVars = *pcEnvVars;
+        size_t const cchVar = pszEqual - pszValue;
+        for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
+        {
+            char *pszCur = papszEnv[iEnvVar];
+            if (   KSUBMIT_ENV_NCMP(pszCur, pszValue, cchVar) == 0
+                && pszCur[cchVar] == '=')
+            {
+                if (cVerbosity > 0)
+                    warnx("replacing '%s' with '%s'", papszEnv[iEnvVar], pszValue);
+                free(papszEnv[iEnvVar]);
+                papszEnv[iEnvVar] = strdup(pszValue);
+                if (!papszEnv[iEnvVar])
+                    return errx(1, "out of memory!");
+                break;
+            }
+        }
+        if (iEnvVar == cEnvVars)
+        {
+            /* Append new variable. We probably need to resize the vector. */
+            if ((cEnvVars + 2) > *pcAllocatedEnvVars)
+            {
+                *pcAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
+                papszEnv = (char **)realloc(papszEnv, *pcAllocatedEnvVars * sizeof(papszEnv[0]));
+                if (!papszEnv)
+                    return errx(1, "out of memory!");
+                *ppapszEnv = papszEnv;
+            }
+            papszEnv[cEnvVars] = strdup(pszValue);
+            if (!papszEnv[cEnvVars])
+                return errx(1, "out of memory!");
+            papszEnv[++cEnvVars]   = NULL;
+            *pcEnvVars = cEnvVars;
+            if (cVerbosity > 0)
+                warnx("added '%s'", papszEnv[iEnvVar]);
+        }
+        else
+        {
+            /* Check for duplicates. */
+            for (iEnvVar++; iEnvVar < cEnvVars; iEnvVar++)
+                if (   KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszValue, cchVar) == 0
+                    && papszEnv[iEnvVar][cchVar] == '=')
+                {
+                    if (cVerbosity > 0)
+                        warnx("removing duplicate '%s'", papszEnv[iEnvVar]);
+                    free(papszEnv[iEnvVar]);
+                    cEnvVars--;
+                    if (iEnvVar != cEnvVars)
+                        papszEnv[iEnvVar] = papszEnv[cEnvVars];
+                    papszEnv[cEnvVars] = NULL;
+                    iEnvVar--;
+                }
+        }
+    }
+    else
+        return errx(1, "Missing '=': -E %s", pszValue);
+
+    return 0;
+}
+
+
+/**
+ * Handles the --unset var option.
+ *
+ * @returns 0 on success, non-zero exit code on error.
+ * @param   papszEnv            The environment vector.
+ * @param   pcEnvVars           Pointer to the variable holding the number of
+ *                              environment variables held by @a papszEnv.
+ * @param   cVerbosity          The verbosity level.
+ * @param   pszVarToRemove      The name of the variable to remove.
+ */
+int kBuiltinOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove)
+{
+    if (strchr(pszVarToRemove, '=') == NULL)
+    {
+        unsigned     cRemoved = 0;
+        size_t const cchVar   = strlen(pszVarToRemove);
+        unsigned     cEnvVars = *pcEnvVars;
+        unsigned     iEnvVar;
+
+        for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
+            if (   KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszVarToRemove, cchVar) == 0
+                && papszEnv[iEnvVar][cchVar] == '=')
+            {
+                if (cVerbosity > 0)
+                    warnx(!cRemoved ? "removing '%s'" : "removing duplicate '%s'", papszEnv[iEnvVar]);
+                free(papszEnv[iEnvVar]);
+                cEnvVars--;
+                if (iEnvVar != cEnvVars)
+                    papszEnv[iEnvVar] = papszEnv[cEnvVars];
+                papszEnv[cEnvVars] = NULL;
+                cRemoved++;
+                iEnvVar--;
+            }
+        *pcEnvVars = cEnvVars;
+
+        if (cVerbosity > 0 && !cRemoved)
+            warnx("not found '%s'", pszVarToRemove);
+    }
+    else
+        return errx(1, "Found invalid variable name character '=' in: -U %s", pszVarToRemove);
+    return 0;
+}
+
+
+
+/**
+ * Handles the --chdir dir option.
+ *
+ * @returns 0 on success, non-zero exit code on error.
+ * @param   pszCwd              The CWD buffer.  Contains current CWD on input,
+ *                              modified by @a pszValue on output.
+ * @param   cbCwdBuf            The size of the CWD buffer.
+ * @param   pszValue            The --chdir value to apply.
+ */
+int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue)
+{
+    size_t cchNewCwd = strlen(pszValue);
+    size_t offDst;
+    if (cchNewCwd)
+    {
+#ifdef HAVE_DOS_PATHS
+        if (*pszValue == '/' || *pszValue == '\\')
+        {
+            if (pszValue[1] == '/' || pszValue[1] == '\\')
+                offDst = 0; /* UNC */
+            else if (pszCwd[1] == ':' && isalpha(pszCwd[0]))
+                offDst = 2; /* Take drive letter from CWD. */
+            else
+                return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", pszCwd, pszValue);
+        }
+        else if (   pszValue[1] == ':'
+                 && isalpha(pszValue[0]))
+        {
+            if (pszValue[2] == '/'|| pszValue[2] == '\\')
+                offDst = 0; /* DOS style absolute path. */
+            else if (   pszCwd[1] == ':'
+                     && tolower(pszCwd[0]) == tolower(pszValue[0]) )
+            {
+                pszValue += 2; /* Same drive as CWD, append drive relative path from value. */
+                cchNewCwd -= 2;
+                offDst = strlen(pszCwd);
+            }
+            else
+            {
+                /* Get current CWD on the specified drive and append value. */
+                int iDrive = tolower(pszValue[0]) - 'a' + 1;
+                if (!_getdcwd(iDrive, pszCwd, cbCwdBuf))
+                    return err(1, "_getdcwd(%d,,) failed", iDrive);
+                pszValue += 2;
+                cchNewCwd -= 2;
+            }
+        }
+#else
+        if (*pszValue == '/')
+            offDst = 0;
+#endif
+        else
+            offDst = strlen(pszCwd); /* Relative path, append to the existing CWD value. */
+
+        /* Do the copying. */
+#ifdef HAVE_DOS_PATHS
+        if (offDst > 0 && pszCwd[offDst - 1] != '/' && pszCwd[offDst - 1] != '\\')
+#else
+        if (offDst > 0 && pszCwd[offDst - 1] != '/')
+#endif
+             pszCwd[offDst++] = '/';
+        if (offDst + cchNewCwd >= cbCwdBuf)
+            return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, pszCwd, pszValue);
+        memcpy(&pszCwd[offDst], pszValue, cchNewCwd + 1);
+    }
+    /* else: relative, no change - quitely ignore. */
+    return 0;
+}
+
diff --git a/src/kmk/kmkbuiltin/cp.c b/src/kmk/kmkbuiltin/cp.c
index f1811b5..5c51bcc 100644
--- a/src/kmk/kmkbuiltin/cp.c
+++ b/src/kmk/kmkbuiltin/cp.c
@@ -221,11 +221,9 @@ kmk_builtin_cp(int argc, char *argv[], char **envp)
 		case 'p':
 			pflag = 1;
 			break;
-#if 0 /* only one -R */
 		case 'r':
 			rflag = 1;
 			break;
-#endif
 		case 'v':
 			vflag = 1;
 			break;
@@ -695,6 +693,7 @@ usage(FILE *fp)
 "   -f  Force. Overrides -i and -n.\n"
 "   -i  Iteractive. Overrides -n and -f.\n"
 "   -n  Don't overwrite any files. Overrides -i and -f.\n"
+"   -v  Verbose.\n"
 "   --ignore-non-existing\n"
 "       Don't fail if the specified source file doesn't exist.\n"
 "   --changed\n"
diff --git a/src/kmk/kmkbuiltin/kDepIDB.c b/src/kmk/kmkbuiltin/kDepIDB.c
index e12d39a..dda407e 100644
--- a/src/kmk/kmkbuiltin/kDepIDB.c
+++ b/src/kmk/kmkbuiltin/kDepIDB.c
@@ -1,4 +1,4 @@
-/* $Id: kDepIDB.c 2856 2016-09-01 02:42:08Z bird $ */
+/* $Id: kDepIDB.c 2955 2016-09-21 19:05:53Z bird $ */
 /** @file
  * kDepIDB - Extract dependency information from a MS Visual C++ .idb file.
  */
@@ -864,7 +864,7 @@ int kmk_builtin_kDepIDB(int argc, char *argv[], char **envp)
      */
     if (!i)
     {
-        depOptimize(fFixCase, fQuiet);
+        depOptimize(fFixCase, fQuiet, NULL /*pszIgnoredExt*/);
         fprintf(pOutput, "%s:", pszTarget);
         depPrint(pOutput);
         if (fStubs)
diff --git a/src/kmk/kmkbuiltin/kDepObj.c b/src/kmk/kmkbuiltin/kDepObj.c
index 96076c0..5cb090a 100644
--- a/src/kmk/kmkbuiltin/kDepObj.c
+++ b/src/kmk/kmkbuiltin/kDepObj.c
@@ -1,4 +1,4 @@
-/* $Id: kDepObj.c 2896 2016-09-08 15:32:09Z bird $ */
+/* $Id: kDepObj.c 2955 2016-09-21 19:05:53Z bird $ */
 /** @file
  * kDepObj - Extract dependency information from an object file.
  */
@@ -973,7 +973,7 @@ static int kDepObjProcessFile(FILE *pInput)
 
 static void usage(const char *a_argv0)
 {
-    printf("usage: %s -o <output> -t <target> [-fqs] <OMF-file>\n"
+    printf("usage: %s -o <output> -t <target> [-fqs] [-e <ignore-ext>] <OMF or COFF file>\n"
            "   or: %s --help\n"
            "   or: %s --version\n",
            a_argv0, a_argv0, a_argv0);
@@ -991,6 +991,7 @@ int kmk_builtin_kDepObj(int argc, char *argv[], char **envp)
     const char *pszTarget = NULL;
     int         fStubs = 0;
     int         fFixCase = 0;
+    const char *pszIgnoreExt = NULL;
     /* Argument parsing. */
     int         fInput = 0;             /* set when we've found input argument. */
     int         fQuiet = 0;
@@ -1009,39 +1010,66 @@ int kmk_builtin_kDepObj(int argc, char *argv[], char **envp)
     {
         if (argv[i][0] == '-')
         {
+            const char *pszValue;
             const char *psz = &argv[i][1];
-            if (*psz == '-')
+            char chOpt;
+            chOpt = *psz++;
+            if (chOpt == '-')
             {
-                if (!strcmp(psz, "-quiet"))
-                    psz = "q";
-                else if (!strcmp(psz, "-help"))
-                    psz = "?";
-                else if (!strcmp(psz, "-version"))
-                    psz = "V";
+                /* Convert long to short option. */
+                if (!strcmp(psz, "quiet"))
+                    chOpt = 'q';
+                else if (!strcmp(psz, "help"))
+                    chOpt = '?';
+                else if (!strcmp(psz, "version"))
+                    chOpt = 'V';
+                else
+                {
+                    fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
+                    usage(argv[0]);
+                    return 2;
+                }
+                psz = "";
             }
 
-            switch (*psz)
+            /*
+             * Requires value?
+             */
+            switch (chOpt)
+            {
+                case 'o':
+                case 't':
+                case 'e':
+                    if (*psz)
+                        pszValue = psz;
+                    else if (++i < argc)
+                        pszValue = argv[i];
+                    else
+                    {
+                        fprintf(stderr, "%s: syntax error: The '-%c' option takes a value.\n", chOpt);
+                        return 2;
+                    }
+                    break;
+
+                default:
+                    pszValue = NULL;
+                    break;
+            }
+
+
+            switch (chOpt)
             {
                 /*
                  * Output file.
                  */
                 case 'o':
                 {
-                    pszOutput = &argv[i][2];
                     if (pOutput)
                     {
                         fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
-                        return 1;
-                    }
-                    if (!*pszOutput)
-                    {
-                        if (++i >= argc)
-                        {
-                            fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
-                            return 1;
-                        }
-                        pszOutput = argv[i];
+                        return 2;
                     }
+                    pszOutput = pszValue;
                     if (pszOutput[0] == '-' && !pszOutput[1])
                         pOutput = stdout;
                     else
@@ -1064,16 +1092,7 @@ int kmk_builtin_kDepObj(int argc, char *argv[], char **envp)
                         fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
                         return 1;
                     }
-                    pszTarget = &argv[i][2];
-                    if (!*pszTarget)
-                    {
-                        if (++i >= argc)
-                        {
-                            fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
-                            return 1;
-                        }
-                        pszTarget = argv[i];
-                    }
+                    pszTarget = pszValue;
                     break;
                 }
 
@@ -1105,6 +1124,20 @@ int kmk_builtin_kDepObj(int argc, char *argv[], char **envp)
                 }
 
                 /*
+                 * Extension to ignore.
+                 */
+                case 'e':
+                {
+                    if (pszIgnoreExt)
+                    {
+                        fprintf(stderr, "%s: syntax error: The '-e' option can only be used once!\n");
+                        return 2;
+                    }
+                    pszIgnoreExt = pszValue;
+                    break;
+                }
+
+                /*
                  * The mandatory version & help.
                  */
                 case '?':
@@ -1120,7 +1153,7 @@ int kmk_builtin_kDepObj(int argc, char *argv[], char **envp)
                 default:
                     fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
                     usage(argv[0]);
-                    return 1;
+                    return 2;
             }
         }
         else
@@ -1178,7 +1211,7 @@ int kmk_builtin_kDepObj(int argc, char *argv[], char **envp)
      */
     if (!i)
     {
-        depOptimize(fFixCase, fQuiet);
+        depOptimize(fFixCase, fQuiet, pszIgnoreExt);
         fprintf(pOutput, "%s:", pszTarget);
         depPrint(pOutput);
         if (fStubs)
diff --git a/src/kmk/kmkbuiltin/kSubmit.c b/src/kmk/kmkbuiltin/kSubmit.c
index fde8e7c..b3132a4 100644
--- a/src/kmk/kmkbuiltin/kSubmit.c
+++ b/src/kmk/kmkbuiltin/kSubmit.c
@@ -1,4 +1,4 @@
-/* $Id: kSubmit.c 2894 2016-09-08 13:27:56Z bird $ */
+/* $Id: kSubmit.c 2959 2016-09-21 20:53:32Z bird $ */
 /** @file
  * kMk Builtin command - submit job to a kWorker.
  */
@@ -573,13 +573,14 @@ static PWORKERINSTANCE kSubmitSelectWorkSpawnNewIfNecessary(unsigned cBitsWorker
  * @param   papszEnvVars        The environment vector.
  * @param   pszCwd              The current directory.
  * @param   fWatcomBrainDamage  The wcc/wcc386 workaround.
+ * @param   fNoPchCaching       Whether to disable precompiled header caching.
  * @param   papszPostCmdArgs    The post command and it's arguments.
  * @param   cPostCmdArgs        Number of post command argument, including the
  *                              command.  Zero if no post command scheduled.
  * @param   pcbMsg              Where to return the message length.
  */
 static void *kSubmitComposeJobMessage(const char *pszExecutable, char **papszArgs, char **papszEnvVars,
-                                      const char *pszCwd, int fWatcomBrainDamage,
+                                      const char *pszCwd, int fWatcomBrainDamage, int fNoPchCaching,
                                       char **papszPostCmdArgs, uint32_t cPostCmdArgs, uint32_t *pcbMsg)
 {
     size_t   cbTmp;
@@ -614,7 +615,8 @@ static void *kSubmitComposeJobMessage(const char *pszExecutable, char **papszArg
         cbMsg += strlen(papszEnvVars[i]) + 1;
     cEnvVars = i;
 
-    cbMsg += 1;
+    cbMsg += 1; /* fWatcomBrainDamage */
+    cbMsg += 1; /* fNoPchCaching */
 
     cbMsg += sizeof(cPostCmdArgs);
     for (i = 0; i < cPostCmdArgs; i++)
@@ -666,6 +668,7 @@ static void *kSubmitComposeJobMessage(const char *pszExecutable, char **papszArg
 
     /* flags */
     *pbCursor++ = fWatcomBrainDamage != 0;
+    *pbCursor++ = fNoPchCaching != 0;
 
     /* post command */
     memcpy(pbCursor, &cPostCmdArgs, sizeof(cPostCmdArgs));
@@ -1095,7 +1098,7 @@ static void kSubmitAtExitCallback(void)
             DWORD cMsElapsed = GetTickCount() - msStartTick;
             DWORD dwWait = WaitForMultipleObjects(cHandles <= MAXIMUM_WAIT_OBJECTS ? cHandles : MAXIMUM_WAIT_OBJECTS,
                                                   ahHandles, FALSE /*bWaitAll*/,
-                                                  cMsElapsed < 1000 ? 1000 - cMsElapsed + 16 : 16);
+                                                  cMsElapsed < 5000 ? 5000 - cMsElapsed + 16 : 16);
             if (   dwWait >= WAIT_OBJECT_0
                 && dwWait <= WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)
             {
@@ -1122,7 +1125,7 @@ static void kSubmitAtExitCallback(void)
             {
                 /* Terminate the whole bunch. */
                 cKillRaids++;
-                if (cKillRaids <= 2)
+                if (cKillRaids == 1 && getenv("KMK_KSUBMIT_NO_KILL") == NULL)
                 {
                     fprintf(stderr, "kmk/kSubmit: Killing %u lingering worker processe(s)!\n", cHandles);
                     for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
@@ -1135,7 +1138,7 @@ static void kSubmitAtExitCallback(void)
                 else
                 {
                     fprintf(stderr, "kmk/kSubmit: Giving up on the last %u worker processe(s). :-(\n", cHandles);
-                    break;
+                    return;
                 }
             }
             else
@@ -1161,210 +1164,11 @@ static void kSubmitAtExitCallback(void)
 }
 
 
-/** The environment variable compare function.
- * We must use case insensitive compare on windows (Path vs PATH).  */
-#ifdef KBUILD_OS_WINDOWS
-# define KSUBMIT_ENV_NCMP   _strnicmp
-#else
-# define KSUBMIT_ENV_NCMP   strncmp
-#endif
-
-
-/**
- * Handles the --set var=value option.
- *
- * @returns 0 on success, non-zero exit code on error.
- * @param   papszEnv            The environment vector.
- * @param   pcEnvVars           Pointer to the variable holding the number of
- *                              environment variables held by @a papszEnv.
- * @param   pcAllocatedEnvVars  Pointer to the variable holding max size of the
- *                              environment vector.
- * @param   cVerbosity          The verbosity level.
- * @param   pszValue            The var=value string to apply.
- */
-static int kSubmitOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
-                            int cVerbosity, const char *pszValue)
-{
-    const char *pszEqual = strchr(pszValue, '=');
-    if (pszEqual)
-    {
-        char   **papszEnv = *ppapszEnv;
-        unsigned iEnvVar;
-        unsigned cEnvVars = *pcEnvVars;
-        size_t const cchVar = pszEqual - pszValue;
-        for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
-        {
-            char *pszCur = papszEnv[iEnvVar];
-            if (   KSUBMIT_ENV_NCMP(pszCur, pszValue, cchVar) == 0
-                && pszCur[cchVar] == '=')
-            {
-                if (cVerbosity > 0)
-                    fprintf(stderr, "kSubmit: replacing '%s' with '%s'\n", papszEnv[iEnvVar], pszValue);
-                free(papszEnv[iEnvVar]);
-                papszEnv[iEnvVar] = xstrdup(pszValue);
-                break;
-            }
-        }
-        if (iEnvVar == cEnvVars)
-        {
-            /* Append new variable. We probably need to resize the vector. */
-            if ((cEnvVars + 2) > *pcAllocatedEnvVars)
-            {
-                *pcAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
-                *ppapszEnv = papszEnv = (char **)xrealloc(papszEnv, *pcAllocatedEnvVars * sizeof(papszEnv[0]));
-            }
-            papszEnv[cEnvVars++] = xstrdup(pszValue);
-            papszEnv[cEnvVars]   = NULL;
-            *pcEnvVars = cEnvVars;
-            if (cVerbosity > 0)
-                fprintf(stderr, "kSubmit: added '%s'\n", papszEnv[iEnvVar]);
-        }
-        else
-        {
-            /* Check for duplicates. */
-            for (iEnvVar++; iEnvVar < cEnvVars; iEnvVar++)
-                if (   KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszValue, cchVar) == 0
-                    && papszEnv[iEnvVar][cchVar] == '=')
-                {
-                    if (cVerbosity > 0)
-                        fprintf(stderr, "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
-                    free(papszEnv[iEnvVar]);
-                    cEnvVars--;
-                    if (iEnvVar != cEnvVars)
-                        papszEnv[iEnvVar] = papszEnv[cEnvVars];
-                    papszEnv[cEnvVars] = NULL;
-                    iEnvVar--;
-                }
-        }
-    }
-    else
-        return errx(1, "Missing '=': -E %s", pszValue);
-
-    return 0;
-}
-
-
-/**
- * Handles the --unset var option.
- *
- * @returns 0 on success, non-zero exit code on error.
- * @param   papszEnv            The environment vector.
- * @param   pcEnvVars           Pointer to the variable holding the number of
- *                              environment variables held by @a papszEnv.
- * @param   cVerbosity          The verbosity level.
- * @param   pszVarToRemove      The name of the variable to remove.
- */
-static int kSubmitOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove)
-{
-    if (strchr(pszVarToRemove, '=') == NULL)
-    {
-        unsigned     cRemoved = 0;
-        size_t const cchVar   = strlen(pszVarToRemove);
-        unsigned     cEnvVars = *pcEnvVars;
-        unsigned     iEnvVar;
-
-        for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
-            if (   KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszVarToRemove, cchVar) == 0
-                && papszEnv[iEnvVar][cchVar] == '=')
-            {
-                if (cVerbosity > 0)
-                    fprintf(stderr, !cRemoved ? "kSubmit: removing '%s'\n"
-                            : "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
-                free(papszEnv[iEnvVar]);
-                cEnvVars--;
-                if (iEnvVar != cEnvVars)
-                    papszEnv[iEnvVar] = papszEnv[cEnvVars];
-                papszEnv[cEnvVars] = NULL;
-                cRemoved++;
-                iEnvVar--;
-            }
-        *pcEnvVars = cEnvVars;
-
-        if (cVerbosity > 0 && !cRemoved)
-            fprintf(stderr, "kSubmit: not found '%s'\n", pszVarToRemove);
-    }
-    else
-        return errx(1, "Found invalid variable name character '=' in: -U %s", pszVarToRemove);
-    return 0;
-}
-
-
-
-/**
- * Handles the --chdir dir option.
- *
- * @returns 0 on success, non-zero exit code on error.
- * @param   pszCwd              The CWD buffer.  Contains current CWD on input,
- *                              modified by @a pszValue on output.
- * @param   cbCwdBuf            The size of the CWD buffer.
- * @param   pszValue            The --chdir value to apply.
- */
-static int kSubmitOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue)
-{
-    size_t cchNewCwd = strlen(pszValue);
-    size_t offDst;
-    if (cchNewCwd)
-    {
-#ifdef HAVE_DOS_PATHS
-        if (*pszValue == '/' || *pszValue == '\\')
-        {
-            if (pszValue[1] == '/' || pszValue[1] == '\\')
-                offDst = 0; /* UNC */
-            else if (pszCwd[1] == ':' && isalpha(pszCwd[0]))
-                offDst = 2; /* Take drive letter from CWD. */
-            else
-                return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", pszCwd, pszValue);
-        }
-        else if (   pszValue[1] == ':'
-                 && isalpha(pszValue[0]))
-        {
-            if (pszValue[2] == '/'|| pszValue[2] == '\\')
-                offDst = 0; /* DOS style absolute path. */
-            else if (   pszCwd[1] == ':'
-                     && tolower(pszCwd[0]) == tolower(pszValue[0]) )
-            {
-                pszValue += 2; /* Same drive as CWD, append drive relative path from value. */
-                cchNewCwd -= 2;
-                offDst = strlen(pszCwd);
-            }
-            else
-            {
-                /* Get current CWD on the specified drive and append value. */
-                int iDrive = tolower(pszValue[0]) - 'a' + 1;
-                if (!_getdcwd(iDrive, pszCwd, cbCwdBuf))
-                    return err(1, "_getdcwd(%d,,) failed", iDrive);
-                pszValue += 2;
-                cchNewCwd -= 2;
-            }
-        }
-#else
-        if (*pszValue == '/')
-            offDst = 0;
-#endif
-        else
-            offDst = strlen(pszCwd); /* Relative path, append to the existing CWD value. */
-
-        /* Do the copying. */
-#ifdef HAVE_DOS_PATHS
-        if (offDst > 0 && pszCwd[offDst - 1] != '/' && pszCwd[offDst - 1] != '\\')
-#else
-        if (offDst > 0 && pszCwd[offDst - 1] != '/')
-#endif
-             pszCwd[offDst++] = '/';
-        if (offDst + cchNewCwd >= cbCwdBuf)
-            return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, pszCwd, pszValue);
-        memcpy(&pszCwd[offDst], pszValue, cchNewCwd + 1);
-    }
-    /* else: relative, no change - quitely ignore. */
-    return 0;
-}
-
-
 static int usage(FILE *pOut,  const char *argv0)
 {
     fprintf(pOut,
             "usage: %s [-Z|--zap-env] [-E|--set <var=val>] [-U|--unset <var=val>]\n"
-            "           [-C|--chdir <dir>] [--wcc-brain-damage]\n"
+            "           [-C|--chdir <dir>] [--wcc-brain-damage] [--no-pch-caching]\n"
             "           [-3|--32-bit] [-6|--64-bit] [-v]\n"
             "           [-P|--post-cmd <cmd> [args]] -- <program> [args]\n"
             "   or: %s --help\n"
@@ -1387,6 +1191,8 @@ static int usage(FILE *pOut,  const char *argv0)
             "  --wcc-brain-damage\n"
             "    Works around wcc and wcc386 (Open Watcom) not following normal\n"
             "    quoting conventions on Windows, OS/2, and DOS.\n"
+            "  --no-pch-caching\n"
+            "    Do not cache precompiled header files because they're being created.\n"
             "  -v,--verbose\n"
             "    More verbose execution.\n"
             "  -P|--post-cmd <cmd> ...\n"
@@ -1400,7 +1206,7 @@ static int usage(FILE *pOut,  const char *argv0)
             "\n"
             ,
             argv0, argv0, argv0);
-    return 1;
+    return 2;
 }
 
 
@@ -1413,11 +1219,11 @@ int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild
     unsigned        cEnvVars;
     char          **papszEnv            = NULL;
     const char     *pszExecutable       = NULL;
-    const char     *pszCwd              = NULL;
     int             iPostCmd            = argc;
     int             cPostCmdArgs        = 0;
     unsigned        cBitsWorker         = g_cArchBits;
     int             fWatcomBrainDamage  = 0;
+    int             fNoPchCaching       = 0;
     int             cVerbosity          = 0;
     size_t const    cbCwdBuf            = GET_PATH_MAX;
     PATH_VAR(szCwd);
@@ -1476,6 +1282,12 @@ int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild
                     continue;
                 }
 
+                if (strcmp(pszArg, "no-pch-caching") == 0)
+                {
+                    fNoPchCaching = 1;
+                    continue;
+                }
+
                 /* convert to short. */
                 if (strcmp(pszArg, "help") == 0)
                     chOpt = 'h';
@@ -1502,7 +1314,7 @@ int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild
                     chOpt = 'e';
                 else
                 {
-                    errx(1, "Unknown option: '%s'", pszArg - 2);
+                    errx(2, "Unknown option: '%s'", pszArg - 2);
                     return usage(stderr, argv[0]);
                 }
                 pszArg = "";
@@ -1541,20 +1353,20 @@ int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild
                         break;
 
                     case 'E':
-                        rcExit = kSubmitOptEnvSet(&papszEnv, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                        rcExit = kBuiltinOptEnvSet(&papszEnv, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                         pChild->environment = papszEnv;
                         if (rcExit == 0)
                             break;
                         return rcExit;
 
                     case 'U':
-                        rcExit = kSubmitOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszValue);
+                        rcExit = kBuiltinOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszValue);
                         if (rcExit == 0)
                             break;
                         return rcExit;
 
                     case 'C':
-                        rcExit = kSubmitOptChDir(szCwd, cbCwdBuf, pszValue);
+                        rcExit = kBuiltinOptChDir(szCwd, cbCwdBuf, pszValue);
                         if (rcExit == 0)
                             break;
                         return rcExit;
@@ -1612,7 +1424,8 @@ int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild
     {
         uint32_t        cbMsg;
         void           *pvMsg   = kSubmitComposeJobMessage(pszExecutable, &argv[iArg], papszEnv, szCwd,
-                                                           fWatcomBrainDamage, &argv[iPostCmd], cPostCmdArgs, &cbMsg);
+                                                           fWatcomBrainDamage, fNoPchCaching,
+                                                           &argv[iPostCmd], cPostCmdArgs, &cbMsg);
         PWORKERINSTANCE pWorker = kSubmitSelectWorkSpawnNewIfNecessary(cBitsWorker, cVerbosity);
         if (pWorker)
         {
diff --git a/src/kmk/kmkbuiltin/md5sum.c b/src/kmk/kmkbuiltin/md5sum.c
index c56dc07..373cf5d 100644
--- a/src/kmk/kmkbuiltin/md5sum.c
+++ b/src/kmk/kmkbuiltin/md5sum.c
@@ -1,4 +1,4 @@
-/* $Id: md5sum.c 2414 2010-09-12 18:42:06Z bird $ */
+/* $Id: md5sum.c 2984 2016-11-01 18:24:11Z bird $ */
 /** @file
  * md5sum.
  */
@@ -299,26 +299,45 @@ static int calc_md5sum(void *pvFile, unsigned char pDigest[16], unsigned fProgre
 {
     int cb;
     int rc = 0;
-    char abBuf[32*1024];
     struct MD5Context Ctx;
     unsigned uPercent = 0;
-    double cbFile = 0.0;
     double off = 0.0;
-
-    if (fProgress)
+    double cbFile = size_file(pvFile);
+
+    /* Get a decent sized buffer assuming we'll be spending more time reading
+       from the storage than doing MD5 sums.  (2MB was choosen based on recent
+       SATA storage benchmarks which used that block size for sequential
+       tests.) We align the buffer address on a 16K boundrary to avoid most
+       transfer alignment issues. */
+    char        *pabBufAligned;
+    size_t const cbBufAlign = 16*1024 - 1;
+    size_t const cbBufMax = 2048*1024;
+    size_t       cbBuf    = cbFile >= cbBufMax ? cbBufMax : ((size_t)cbFile + cbBufAlign) & ~(size_t)cbBufAlign;
+    char        *pabBuf   = (char *)malloc(cbBuf + cbBufAlign);
+    if (pabBuf)
+        pabBufAligned = (char *)(((uintptr_t)pabBuf + cbBufAlign) & ~(uintptr_t)cbBufAlign );
+    else
     {
-        cbFile = size_file(pvFile);
-        if (cbFile < 1024*1024)
-            fProgress = 0;
+        do
+        {
+            cbBuf /= 2;
+            pabBuf = (char *)malloc(cbBuf);
+        } while (!pabBuf && cbBuf > 4096);
+        if (!pabBuf)
+            return ENOMEM;
+        pabBufAligned = pabBuf;
     }
 
+    if (cbFile < cbBuf * 4)
+        fProgress = 0;
+
     MD5Init(&Ctx);
     for (;;)
     {
         /* process a chunk. */
-        cb = read_file(pvFile, abBuf, sizeof(abBuf));
+        cb = read_file(pvFile, pabBufAligned, cbBuf);
         if (cb > 0)
-            MD5Update(&Ctx, (unsigned char *)&abBuf[0], cb);
+            MD5Update(&Ctx, (unsigned char *)pabBufAligned, cb);
         else if (!cb)
             break;
         else
@@ -348,6 +367,7 @@ static int calc_md5sum(void *pvFile, unsigned char pDigest[16], unsigned fProgre
     if (fProgress)
         printf("\b\b\b\b    \b\b\b\b");
 
+    free(pabBuf);
     return rc;
 }
 
@@ -571,7 +591,7 @@ static int md5sum_file(const char *pszFilename, unsigned fText, unsigned fQuiet,
     void *pvFile;
 
     /*
-     * Calcuate and print the MD5 sum for one file.
+     * Calculate and print the MD5 sum for one file.
      */
     pvFile = open_file(pszFilename, fText);
     if (pvFile)
diff --git a/src/kmk/kmkbuiltin/redirect.c b/src/kmk/kmkbuiltin/redirect.c
index cd4af45..5f5a558 100644
--- a/src/kmk/kmkbuiltin/redirect.c
+++ b/src/kmk/kmkbuiltin/redirect.c
@@ -1,4 +1,4 @@
-/* $Id: redirect.c 2839 2016-08-25 21:46:44Z bird $ */
+/* $Id: redirect.c 2916 2016-09-15 11:41:42Z bird $ */
 /** @file
  * kmk_redirect - Do simple program <-> file redirection (++).
  */
@@ -29,20 +29,37 @@
 #ifdef __APPLE__
 # define _POSIX_C_SOURCE 1 /* 10.4 sdk and unsetenv */
 #endif
-#include "config.h"
+#include "make.h"
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
+# include <process.h>
+#endif
 #if defined(_MSC_VER)
 # include <ctype.h>
 # include <io.h>
-# include <direct.h>
-# include <process.h>
 # include "quote_argv.h"
 #else
 # include <unistd.h>
+# include <spawn.h>
+#endif
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include "err.h"
+#include "kbuild_version.h"
+#include "kmkbuiltin.h"
+#ifdef KMK
+# ifdef KBUILD_OS_WINDOWS
+#  include "sub_proc.h"
+#  include "pathstuff.h"
+# endif
+# include "job.h"
+# include "variable.h"
 #endif
 
 #ifdef __OS2__
@@ -53,12 +70,13 @@
 # endif
 #endif
 
+#if !defined(KBUILD_OS_WINDOWS) && !defined(KBUILD_OS_OS2)
+# define USE_POSIX_SPAWN
+#endif
+
 
-/*********************************************************************************************************************************
-*   Global Variables                                                                                                             *
-*********************************************************************************************************************************/
-/** Number of times the '-v' switch was seen. */
-static unsigned g_cVerbosity = 0;
+/* String + strlen tuple. */
+#define TUPLE(a_sz)     a_sz, sizeof(a_sz) - 1
 
 
 #if defined(_MSC_VER)
@@ -106,8 +124,11 @@ static const char *name(const char *pszName)
 
 static int usage(FILE *pOut,  const char *argv0)
 {
+    argv0 = name(argv0);
     fprintf(pOut,
-            "usage: %s [-[rwa+tb]<fd> <file>] [-c<fd>] [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage] [-v] -- <program> [args]\n"
+            "usage: %s [-[rwa+tb]<fd> <file>] [-d<fd>=<src-fd>] [-c<fd>]\n"
+            "           [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage]\n"
+            "           [-v] -- <program> [args]\n"
             "   or: %s --help\n"
             "   or: %s --version\n"
             "\n"
@@ -117,6 +138,9 @@ static int usage(FILE *pOut,  const char *argv0)
             "   o = stdout\n"
             "   e = stderr\n"
             "\n"
+            "The -d switch duplicate the right hand file descriptor (src-fd) to the left\n"
+            "hand side one (fd).\n"
+            "\n"
             "The -c switch will close the specified file descriptor.\n"
             "\n"
             "The -Z switch zaps the environment.\n"
@@ -138,536 +162,1497 @@ static int usage(FILE *pOut,  const char *argv0)
             "/usr/bin/env on steroids.\n"
             ,
             argv0, argv0, argv0);
-    return 1;
+    return 2;
 }
 
 
-int main(int argc, char **argv, char **envp)
+/**
+ * Decoded file descriptor operations.
+ */
+typedef struct REDIRECTORDERS
 {
-    int i;
-    int j;
-#if defined(_MSC_VER)
-    intptr_t rc;
+    enum {
+        kRedirectOrder_Invalid = 0,
+        kRedirectOrder_Close,
+        kRedirectOrder_Open,
+        kRedirectOrder_Dup,
+    }           enmOrder;
+    /** The target file handle. */
+    int         fdTarget;
+    /** The source file name, -1 on close only.
+     * This is an opened file if pszFilename is set.  */
+    int         fdSource;
+    /** Whether to remove the file on failure cleanup. */
+    int         fRemoveOnFailure;
+    /** The open flags (for O_TEXT/O_BINARY) on windows. */
+    int         fOpen;
+    /** The filename - NULL if close only. */
+    const char *pszFilename;
+#ifndef USE_POSIX_SPAWN
+    /** Saved file descriptor. */
+    int         fdSaved;
+    /** Saved flags. */
+    int         fSaved;
 #endif
-    FILE *pStdErr = stderr;
-    FILE *pStdOut = stdout;
-    int fWatcomBrainDamage = 0;
+} REDIRECTORDERS;
 
-    /*
-     * Parse arguments.
-     */
-    if (argc <= 1)
-        return usage(pStdErr, name(argv[0]));
-    for (i = 1; i < argc; i++)
+
+#ifdef _MSC_VER
+
+/**
+ * Safe way of getting the OS handle of a file descriptor without triggering
+ * invalid parameter handling.
+ *
+ * @returns The handle value if open, INVALID_HANDLE_VALUE if not.
+ * @param   fd                  The file descriptor in question.
+ */
+static HANDLE mscGetOsHandle(int fd)
+{
+    intptr_t                    hHandle;
+    _invalid_parameter_handler  pfnOld = _get_invalid_parameter_handler();
+    _set_invalid_parameter_handler(ignore_invalid_parameter);
+    hHandle = _get_osfhandle(fd);
+    _set_invalid_parameter_handler(pfnOld);
+    return hHandle != -1 ? (HANDLE)hHandle : INVALID_HANDLE_VALUE;
+}
+
+/**
+ * Checks if the specified file descriptor is open.
+ *
+ * @returns K_TRUE if open, K_FALSE if not.
+ * @param   fd                  The file descriptor in question.
+ */
+static KBOOL mscIsOpenFile(int fd)
+{
+    return mscGetOsHandle(fd) != INVALID_HANDLE_VALUE;
+}
+
+/**
+ * Checks if the native handle is inheritable.
+ *
+ * @returns K_TRUE if it is, K_FALSE if it isn't or isn't a valid handle.
+ * @param   hHandle             The native handle.
+ */
+static KBOOL mscIsNativeHandleInheritable(HANDLE hHandle)
+{
+    DWORD fFlags = 0;
+    if (GetHandleInformation(hHandle, &fFlags))
+        return (fFlags & HANDLE_FLAG_INHERIT) != 0;
+    return K_FALSE;
+}
+
+/**
+ * Checks if the file descriptor is inheritable or not.
+ *
+ * @returns K_TRUE if it is, K_FALSE if it isn't or isn't a valid descriptor.
+ * @param   fd                  The file descriptor in question.
+ */
+static KBOOL mscIsInheritable(int fd)
+{
+    HANDLE hHandle = mscGetOsHandle(fd);
+    if (hHandle != INVALID_HANDLE_VALUE)
+        return mscIsNativeHandleInheritable(hHandle);
+    return K_FALSE;
+}
+
+/**
+ * A dup3 like function.
+ *
+ * @returns fdNew on success, -1 on failure w/ error details written to pStdErr.
+ * @param   fdSource            The source descriptor.
+ * @param   fdNew               The new descriptor.
+ * @param   fFlags              The inherit and text/binary mode flag.
+ * @param   pStdErr             Working stderr to write error details to.
+ */
+static int mscDup3(int fdSource, int fdNew, int fFlags, FILE *pStdErr)
+{
+    if (!fFlags & _O_NOINHERIT)
     {
-        if (argv[i][0] == '-')
-        {
-            int fd;
-            int fdOpened;
-            int fOpen;
-            char *psz = &argv[i][1];
-            if (*psz == '-')
-            {
-                /* '--' ? */
-                if (!psz[1])
-                {
-                    i++;
-                    break;
-                }
+        /* ASSUMES fFlags doesn't include any changing _O_TEXT/_O_BINARY. */
+        int fdDup = _dup2(fdSource, fdNew);
+        if (fdDup != -1)
+            return fdDup;
+        fprintf(pStdErr, "%s: _dup2(%d,%d) failed: %s\n", g_progname, fdSource, fdNew, strerror(errno));
+    }
+    else
+    {
+        HANDLE   hSource = mscGetOsHandle(fdSource);
+        unsigned cTries  = 0;
+        int      aFdTries[48];
 
-                /* convert to short. */
-                if (!strcmp(psz, "-help"))
-                    psz = "h";
-                else if (!strcmp(psz, "-version"))
-                    psz = "V";
-                else if (!strcmp(psz, "-env"))
-                    psz = "E";
-                else if (!strcmp(psz, "-chdir"))
-                    psz = "C";
-                else if (!strcmp(psz, "-zap-env"))
-                    psz = "Z";
-                else if (!strcmp(psz, "-close"))
-                    psz = "c";
-                else if (!strcmp(psz, "-wcc-brain-damage"))
-                {
-                    fWatcomBrainDamage = 1;
-                    continue;
-                }
-            }
+        if (hSource != INVALID_HANDLE_VALUE)
+        {
+            HANDLE hCurProc = GetCurrentProcess();
+            BOOL   fInherit = !(fFlags & _O_NOINHERIT);
 
             /*
-             * Deal with the obligatory help and version switches first.
+             * Make sure the old descriptor is closed and can be used again.
              */
-            if (*psz == 'h')
-            {
-                usage(pStdOut, name(argv[0]));
-                return 0;
-            }
-            if (*psz == 'V')
-            {
-                printf("kmk_redirect - kBuild version %d.%d.%d (r%u)\n"
-                       "Copyright (C) 2007-2012 knut st. osmundsen\n",
-                       KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
-                       KBUILD_SVN_REV);
-                return 0;
-            }
+            _invalid_parameter_handler pfnOld = _get_invalid_parameter_handler();
+            _set_invalid_parameter_handler(ignore_invalid_parameter);
+            close(fdNew);
+            _set_invalid_parameter_handler(pfnOld);
 
             /*
-             * Environment switch?
+             * Duplicate the source handle till we've got a match.
              */
-            if (*psz == 'E')
+            for (;;)
             {
-                psz++;
-                if (*psz == ':' || *psz == '=')
-                    psz++;
-                else
-                {
-                    if (i + 1 >= argc)
-                    {
-                        fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
-                        return 1;
-                    }
-                    psz = argv[++i];
-                }
-#ifdef __OS2__
-                if (    !strncmp(psz, "BEGINLIBPATH=",  sizeof("BEGINLIBPATH=") - 1)
-                    ||  !strncmp(psz, "ENDLIBPATH=",    sizeof("ENDLIBPATH=") - 1)
-                    ||  !strncmp(psz, "LIBPATHSTRICT=", sizeof("LIBPATHSTRICT=") - 1))
-                {
-                    ULONG ulVar = *psz == 'B' ? BEGIN_LIBPATH
-                                : *psz == 'E' ? END_LIBPATH
-                                :               LIBPATHSTRICT;
-                    const char *pszVal = strchr(psz, '=') + 1;
-                    APIRET rc = DosSetExtLIBPATH(pszVal, ulVar);
-                    if (rc)
-                    {
-                        fprintf(pStdErr, "%s: error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu\n",
-                                name(argv[0]), pszVal, pszVal - psz - 1, psz, ulVar, rc);
-                        return 1;
-                    }
-                }
-                else
-#endif /* __OS2__ */
+                HANDLE hDup = INVALID_HANDLE_VALUE;
+                if (DuplicateHandle(hCurProc, hSource, hCurProc, &hDup, 0 /* DesiredAccess */,
+                                    fInherit, DUPLICATE_SAME_ACCESS))
                 {
-                    const char *pchEqual = strchr(psz, '=');
-                    if (pchEqual && pchEqual[1] != '\0')
+                    int fdDup = _open_osfhandle((intptr_t)hDup, fFlags);
+                    if (fdDup != -1)
                     {
-                        if (putenv(psz))
+                        if (fdDup == fdNew)
                         {
-                            fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
-                            return 1;
+                            while (cTries-- > 0)
+                                close(aFdTries[cTries]);
+                            return fdDup;
                         }
+
+                        aFdTries[cTries++] = fdDup;
+                        if (   fdDup < fdNew
+                            && cTries < K_ELEMENTS(aFdTries))
+                            continue;
+                        fprintf(pStdErr, "%s: mscDup3(%d,%d): giving up! (last fdDup=%d)\n",
+                                g_progname, fdSource, fdNew, fdDup);
                     }
                     else
                     {
-                        size_t cchVar = pchEqual ? (size_t)(pchEqual - psz) : strlen(psz);
-                        char *pszCopy = (char *)malloc(cchVar + 2);
-                        memcpy(pszCopy, psz, cchVar);
-
-#if defined(_MSC_VER) || defined(__OS2__)
-                        pszCopy[cchVar] = '=';
-                        pszCopy[cchVar + 1] = '\0';
-                        if (putenv(pszCopy))
-                        {
-                            fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
-                            return 1;
-                        }
-#else
-                        pszCopy[cchVar] = '\0';
-                        if (unsetenv(pszCopy))
-                        {
-                            fprintf(pStdErr, "%s: error: unsetenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
-                            return 1;
-                        }
-#endif
-                        free(pszCopy);
+                        fprintf(pStdErr, "%s: _open_osfhandle(%#x) failed: %u\n", g_progname, hDup, strerror(errno));
+                        CloseHandle(hDup);
                     }
                 }
-                continue;
-            }
-
-            /*
-             * Change directory switch?
-             */
-            if (*psz == 'C')
-            {
-                psz++;
-                if (*psz == ':' || *psz == '=')
-                    psz++;
                 else
-                {
-                    if (i + 1 >= argc)
-                    {
-                        fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
-                        return 1;
-                    }
-                    psz = argv[++i];
-                }
-                if (!chdir(psz))
-                    continue;
-#ifdef _MSC_VER
-                {
-                    /* drop trailing slash if any. */
-                    size_t cch = strlen(psz);
-                    if (    cch > 2
-                        &&  (psz[cch - 1] == '/' || psz[cch - 1] == '\\')
-                        &&  psz[cch - 1] != ':')
-                    {
-                        int rc2;
-                        char *pszCopy = strdup(psz);
-                        do  pszCopy[--cch] = '\0';
-                        while (    cch > 2
-                               &&  (pszCopy[cch - 1] == '/' || pszCopy[cch - 1] == '\\')
-                               &&  pszCopy[cch - 1] != ':');
-                        rc2 = chdir(pszCopy);
-                        free(pszCopy);
-                        if (!rc2)
-                            continue;
-                    }
-                }
-#endif
-                fprintf(pStdErr, "%s: error: chdir(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
-                return 1;
+                    fprintf(pStdErr, "%s: DuplicateHandle(%#x) failed: %u\n", g_progname, hSource, GetLastError());
+                break;
             }
 
-            /*
-             * Zap environment switch?
-             * This is a bit of a hack.
-             */
-            if (*psz == 'Z')
-            {
-                unsigned j = 0;
-                while (envp[j] != NULL)
-                    j++;
-                while (j-- > 0)
-                {
-                    char *pszEqual = strchr(envp[j], '=');
-                    char *pszCopy;
+            while (cTries-- > 0)
+                close(aFdTries[cTries]);
+        }
+        else
+            fprintf(pStdErr, "%s: mscDup3(%d,%d): source descriptor is invalid!\n", g_progname, fdSource, fdNew);
+    }
+    return -1;
+}
 
-                    if (pszEqual)
-                        *pszEqual = '\0';
-                    pszCopy = strdup(envp[j]);
-                    if (pszEqual)
-                        *pszEqual = '=';
+#endif /* _MSC_VER */
 
-#if defined(_MSC_VER) || defined(__OS2__)
-                    putenv(pszCopy);
+static KBOOL kRedirectHasConflict(int fd, unsigned cOrders, REDIRECTORDERS *paOrders)
+{
+    while (cOrders-- > 0)
+        if (paOrders[cOrders].fdTarget == fd)
+            return K_TRUE;
+    return K_FALSE;
+}
+
+
+/**
+ * Creates a file descriptor for @a pszFilename that does not conflict with any
+ * previous orders.
+ *
+ * We need to be careful that there isn't a close or dup targetting the
+ * temporary file descriptor we return.  Also, we need to take care with the
+ * descriptor's inheritability.  It should only be inheritable if the returned
+ * descriptor matches the target descriptor (@a fdTarget).
+ *
+ * @returns File descriptor on success, -1 & err/errx on failure.
+ *
+ *          The returned file descriptor is not inherited (i.e. close-on-exec),
+ *          unless it matches @a fdTarget
+ *
+ * @param   pszFilename         The filename to open.
+ * @param   fOpen               The open flags.
+ * @param   fMode               The file creation mode (if applicable).
+ * @param   cOrders             The number of orders.
+ * @param   paOrders            The order array.
+ * @param   fRemoveOnFailure    Whether to remove the file on failure.
+ * @param   fdTarget            The target descriptor.
+ */
+static int kRedirectOpenWithoutConflict(const char *pszFilename, int fOpen, mode_t fMode,
+                                        unsigned cOrders, REDIRECTORDERS *paOrders, int fRemoveOnFailure, int fdTarget)
+{
+#ifdef _O_NOINHERIT
+    int const   fNoInherit = _O_NOINHERIT;
+#elif defined(O_NOINHERIT)
+    int const   fNoInherit = O_NOINHERIT;
+#elif defined(O_CLOEXEC)
+    int const   fNoInherit = O_CLOEXEC;
 #else
-                    unsetenv(pszCopy);
+# error "port me"
+#endif
+    int         aFdTries[32];
+    int         cTries;
+    int         fdOpened;
+
+#ifdef KBUILD_OS_WINDOWS
+    if (strcmp(pszFilename, "/dev/null") == 0)
+        pszFilename = "nul";
+#endif
+
+    /* Open it first. */
+    fdOpened = open(pszFilename, fOpen | fNoInherit, fMode);
+    if (fdOpened < 0)
+        return err(-1, "open(%s,%#x,) failed", pszFilename, fOpen);
+
+    /* Check for conflicts. */
+    if (!kRedirectHasConflict(fdOpened, cOrders, paOrders))
+    {
+        if (fdOpened != fdTarget)
+            return fdOpened;
+#ifndef _MSC_VER /* Stupid, stupid MSVCRT!  No friggin way of making a handle inheritable (or not). */
+        if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) != -1)
+            return fdOpened;
+#endif
+    }
+
+    /*
+     * Do conflict resolving.
+     */
+    cTries = 1;
+    aFdTries[cTries++] = fdOpened;
+    while (cTries < K_ELEMENTS(aFdTries))
+    {
+        fdOpened = open(pszFilename, fOpen | fNoInherit, fMode);
+        if (fdOpened >= 0)
+        {
+            if (   !kRedirectHasConflict(fdOpened, cOrders, paOrders)
+#ifdef _MSC_VER
+                && fdOpened != fdTarget
+#endif
+                )
+            {
+#ifndef _MSC_VER
+                if (   fdOpened != fdTarget
+                    || fcntl(fdOpened, F_SETFD, FD_CLOEXEC) != -1)
 #endif
-                    free(pszCopy);
+                {
+                    while (cTries-- > 0)
+                        close(aFdTries[cTries]);
+                    return fdOpened;
                 }
-                continue;
             }
 
-            /*
-             * Verbose operation switch?
-             */
-            if (*psz == 'v')
+        }
+        else
+        {
+            err(-1, "open(%s,%#x,) #%u failed", pszFilename, cTries + 1, fOpen);
+            break;
+        }
+        aFdTries[cTries++] = fdOpened;
+    }
+
+    /*
+     * Give up.
+     */
+    if (fdOpened >= 0)
+        errx(-1, "failed to find a conflict free file descriptor for '%s'!", pszFilename);
+
+    while (cTries-- > 0)
+        close(aFdTries[cTries]);
+    return -1;
+}
+
+#ifndef USE_POSIX_SPAWN
+
+/**
+ * Saves a file handle to one which isn't inherited and isn't affected by the
+ * file orders.
+ *
+ * @returns 0 on success, non-zero exit code on failure.
+ * @param   pToSave         Pointer to the file order to save the target
+ *                          descriptor of.
+ * @param   cOrders         Number of file orders.
+ * @param   paOrders        The array of file orders.
+ * @param   ppWorkingStdErr Pointer to a pointer to a working stderr.  This will
+ *                          get replaced if we're saving stderr, so that we'll
+ *                          keep having a working one to report failures to.
+ */
+static int kRedirectSaveHandle(REDIRECTORDERS *pToSave, unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
+{
+    int fdToSave = pToSave->fdTarget;
+    int rcRet    = 10;
+
+    /*
+     * First, check if there's actually handle here that needs saving.
+     */
+# ifdef KBUILD_OS_WINDOWS
+    HANDLE hToSave = mscGetOsHandle(fdToSave);
+    if (hToSave != INVALID_HANDLE_VALUE)
+    {
+        pToSave->fSaved = _setmode(fdToSave, _O_BINARY);
+        if (pToSave->fSaved != _O_BINARY)
+            _setmode(fdToSave, pToSave->fSaved);
+        if (!mscIsNativeHandleInheritable(hToSave))
+            pToSave->fSaved |= _O_NOINHERIT;
+    }
+    if (hToSave != INVALID_HANDLE_VALUE)
+# else
+    pToSave->fSaved = fcntl(pToSave->fdTarget, F_GETFD, 0);
+    if (pToSave->fSaved != -1)
+# endif
+    {
+        /*
+         * Try up to 32 times to get a duplicate descriptor that doesn't conflict.
+         */
+# ifdef KBUILD_OS_WINDOWS
+        HANDLE hCurProc = GetCurrentProcess();
+# endif
+        int aFdTries[32];
+        int cTries = 0;
+        do
+        {
+            /* Duplicate the handle (windows makes this complicated). */
+            int fdDup;
+# ifdef KBUILD_OS_WINDOWS
+            HANDLE hDup = INVALID_HANDLE_VALUE;
+            if (!DuplicateHandle(hCurProc, hToSave, hCurProc, &hDup, 0 /* DesiredAccess */,
+                                FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
             {
-                g_cVerbosity++;
-                continue;
+                fprintf(*ppWorkingStdErr, "%s: DuplicateHandle(%#x) failed: %u\n", g_progname, hToSave, GetLastError());
+                break;
             }
-
-            /*
-             * Close the specified file descriptor (no stderr/out/in aliases).
-             */
-            if (*psz == 'c')
+            fdDup = _open_osfhandle((intptr_t)hDup, pToSave->fSaved | _O_NOINHERIT);
+            if (fdDup == -1)
+            {
+                fprintf(*ppWorkingStdErr, "%s: _open_osfhandle(%#x) failed: %u\n", g_progname, hDup, strerror(errno));
+                CloseHandle(hDup);
+                break;
+            }
+# else
+            fdDup = dup(fdToSave);
+            if (fdDup == -1)
+            {
+                fprintf(*ppWorkingStdErr, "%s: dup(%#x) failed: %u\n", g_progname, fdToSave, strerror(errno));
+                break;
+            }
+#endif
+            /* Is the duplicate usable? */
+            if (!kRedirectHasConflict(fdDup, cOrders, paOrders))
             {
-                psz++;
-                if (!*psz)
+                pToSave->fdSaved = fdDup;
+                if (   *ppWorkingStdErr == stderr
+                    && fdToSave == fileno(*ppWorkingStdErr))
                 {
-                    i++;
-                    if (i >= argc)
+                    *ppWorkingStdErr = fdopen(fdDup, "wt");
+                    if (*ppWorkingStdErr == NULL)
                     {
-                        fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
-                        return 1;
+                        fprintf(stderr, "%s: fdopen(%d,\"wt\") failed: %s\n", g_progname, fdDup, strerror(errno));
+                        *ppWorkingStdErr = stderr;
+                        close(fdDup);
+                        break;
                     }
-                    psz = argv[i];
                 }
+                rcRet = 0;
+                break;
+            }
 
-                fd = (int)strtol(psz, &psz, 0);
-                if (!fd || *psz)
-                {
-                    fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
-                    return 1;
+            /* Not usuable, stash it and try again. */
+            aFdTries[cTries++] = fdDup;
+        } while (cTries < K_ELEMENTS(aFdTries));
 
-                }
-                if (fd < 0)
+        /*
+         * Clean up unused duplicates.
+         */
+        while (cTries-- > 0)
+            close(aFdTries[cTries]);
+    }
+    else
+    {
+        /*
+         * Nothing to save.
+         */
+        pToSave->fdSaved = -1;
+        rcRet = 0;
+    }
+    return rcRet;
+}
+
+
+/**
+ * Cleans up the file operation orders.
+ *
+ * This does not restore stuff, just closes handles we've opened for the guest.
+ *
+ * @param   cOrders         Number of file operation orders.
+ * @param   paOrders        The file operation orders.
+ * @param   fFailed         Set if it's a failure.
+ */
+static void kRedirectCleanupFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, KBOOL fFailure)
+{
+    unsigned i = cOrders;
+    while (i-- > 0)
+    {
+        if (   paOrders[i].enmOrder == kRedirectOrder_Open
+            && paOrders[i].fdSource != -1)
+        {
+            close(paOrders[i].fdSource);
+            paOrders[i].fdSource = -1;
+            if (   fFailure
+                && paOrders[i].fRemoveOnFailure
+                && paOrders[i].pszFilename)
+                remove(paOrders[i].pszFilename);
+        }
+    }
+}
+
+
+/**
+ * Restores the target file descriptors affected by the file operation orders.
+ *
+ * @param   cOrders         Number of file operation orders.
+ * @param   paOrders        The file operation orders.
+ * @param   ppWorkingStdErr Pointer to a pointer to the working stderr.  If this
+ *                          is one of the saved file descriptors, we'll restore
+ *                          it to stderr.
+ */
+static void kRedirectRestoreFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
+{
+    int iSavedErrno = errno;
+    unsigned i = cOrders;
+    while (i-- > 0)
+    {
+        if (paOrders[i].fdSaved != -1)
+        {
+            KBOOL fRestoreStdErr = *ppWorkingStdErr != stderr
+                                 && paOrders[i].fdSaved == fileno(*ppWorkingStdErr);
+
+#ifdef KBUILD_OS_WINDOWS
+            if (mscDup3(paOrders[i].fdSaved, paOrders[i].fdTarget, paOrders[i].fSaved, *ppWorkingStdErr) != -1)
+#else
+            if (dup2(paOrders[i].fdSaved, paOrders[i].fdTarget) != -1)
+#endif
+            {
+                close(paOrders[i].fdSaved);
+                paOrders[i].fdSaved = -1;
+
+                if (fRestoreStdErr)
                 {
-                    fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
-                    return 1;
+                    *ppWorkingStdErr = stderr;
+                    assert(fileno(stderr) == paOrders[i].fdTarget);
                 }
-                /** @todo deal with stderr */
-                safeCloseFd(fd);
-                continue;
             }
+#ifndef KBUILD_OS_WINDOWS
+            else
+                fprintf(*ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s",
+                        g_progname, paOrders[i].fdSaved, paOrders[i].fdTarget, strerror(errno));
+#endif
+        }
+
+#ifndef KBUILD_OS_WINDOWS
+        if (paOrders[i].fSaved != -1)
+        {
+            if (fcntl(paOrders[i].fdTarget, F_SETFD, paOrders[i].fSaved & FD_CLOEXEC) == -1)
+                paOrders[i].fSaved = -1;
+            else
+                fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,%s) failed: %s",
+                        g_progname, paOrders[i].fdTarget, paOrders[i].fSaved & FD_CLOEXEC ? "FD_CLOEXEC" : "0", strerror(errno));
+        }
+#endif
+    }
+    errno = iSavedErrno;
+}
 
-            /*
-             * Parse a file descriptor argument.
-             */
 
-            /* mode */
-            switch (*psz)
+/**
+ * Executes the file operation orders.
+ *
+ * @returns 0 on success, exit code on failure.
+ * @param   cOrders         Number of file operation orders.
+ * @param   paOrders        File operation orders to execute.
+ * @param   ppWorkingStdErr Where to return a working stderr (mainly for
+ *                          kRedirectRestoreFdOrders).
+ */
+static int kRedirectExecFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
+{
+    unsigned i;
+
+    *ppWorkingStdErr = stderr;
+    for (i = 0; i < cOrders; i++)
+    {
+        int rcExit = 10;
+        switch (paOrders[i].enmOrder)
+        {
+            case kRedirectOrder_Close:
             {
-                case 'r':
-                    psz++;
-                    if (*psz == '+')
+                /* If the handle isn't used by any of the following operation,
+                   just mark it as non-inheritable if necessary. */
+                int const fdTarget = paOrders[i].fdTarget;
+                unsigned j;
+                for (j = i + 1; j < cOrders; j++)
+                    if (paOrders[j].fdTarget == fdTarget)
+                        break;
+# ifdef _MSC_VER
+                if (j >= cOrders && !mscIsInheritable(fdTarget))
+                    rcExit = 0;
+# else
+                if (j >= cOrders)
+                {
+                    paOrders[j].fSaved = fcntl(fdTarget, F_GETFD, 0);
+                    if (paOrders[j].fSaved != -1)
                     {
-                        fOpen = O_RDWR;
-                        psz++;
+                        if (paOrders[j].fSaved & FD_CLOEXEC)
+                            rcExit = 0;
+                        else if (   fcntl(fdTarget, F_SETFD, FD_CLOEXEC) != -1
+                                 || errno == EBADF)
+                            rcExit = 0;
+                        else
+                            fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,FD_CLOEXEC) failed: %s",
+                                    g_progname, fdTarget, strerror(errno));
                     }
+                    else if (errno == EBADF)
+                        rcExit = 0;
                     else
-                        fOpen = O_RDONLY;
-                    break;
+                        fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_GETFD,0) failed: %s", g_progname, fdTarget, strerror(errno));
+                }
+# endif
+                else
+                    rcExit = kRedirectSaveHandle(&paOrders[i], cOrders, paOrders, ppWorkingStdErr);
+                break;
+            }
 
-                case 'w':
-                    psz++;
-                    if (*psz == '+')
-                    {
-                        psz++;
-                        fOpen = O_RDWR | O_CREAT | O_TRUNC;
-                    }
+            case kRedirectOrder_Dup:
+            case kRedirectOrder_Open:
+                rcExit = kRedirectSaveHandle(&paOrders[i], cOrders, paOrders, ppWorkingStdErr);
+                if (rcExit == 0)
+                {
+                    if (dup2(paOrders[i].fdSource, paOrders[i].fdTarget) != -1)
+                        rcExit = 0;
                     else
-                        fOpen = O_WRONLY | O_CREAT | O_TRUNC;
-                    break;
-
-                case 'a':
-                    psz++;
-                    if (*psz == '+')
                     {
-                        psz++;
-                        fOpen = O_RDWR | O_CREAT | O_APPEND;
+                        if (paOrders[i].enmOrder == kRedirectOrder_Open)
+                            fprintf(*ppWorkingStdErr, "%s: dup2(%d [%s],%d) failed: %s", g_progname, paOrders[i].fdSource,
+                                    paOrders[i].pszFilename, paOrders[i].fdTarget, strerror(errno));
+                        else
+                            fprintf(*ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s",
+                                    g_progname, paOrders[i].fdSource, paOrders[i].fdTarget, strerror(errno));
+                        rcExit = 10;
                     }
-                    else
-                        fOpen = O_WRONLY | O_CREAT | O_APPEND;
-                    break;
+                }
+                break;
 
-                case 'i': /* make sure stdin is read-only. */
-                    fOpen = O_RDONLY;
-                    break;
+            default:
+                fprintf(*ppWorkingStdErr, "%s: error! invalid enmOrder=%d\n", g_progname, paOrders[i].enmOrder);
+                rcExit = 99;
+                break;
+        }
 
-                case '+':
-                    fprintf(pStdErr, "%s: syntax error: Unexpected '+' in '%s'\n", name(argv[0]), argv[i]);
-                    return 1;
+        if (rcExit != 0)
+        {
+            kRedirectRestoreFdOrders(i, paOrders, ppWorkingStdErr);
+            return rcExit;
+        }
+    }
 
-                default:
-                    fOpen = O_RDWR | O_CREAT | O_TRUNC;
-                    break;
-            }
+    return 0;
+}
 
-            /* binary / text modifiers */
-            switch (*psz)
-            {
-                case 'b':
-#ifdef O_BINARY
-                    fOpen |= O_BINARY;
+#endif /* !USE_POSIX_SPAWN */
+
+
+/**
+ * Does the child spawning .
+ *
+ * @returns Exit code.
+ * @param   pszExecutable       The child process executable.
+ * @param   cArgs               Number of arguments.
+ * @param   papszArgs           The child argument vector.
+ * @param   fWatcomBrainDamage  Whether MSC need to do quoting according to
+ *                              weird Watcom WCC rules.
+ * @param   papszEnv            The child environment vector.
+ * @param   pszCwd              The current working directory of the child.
+ * @param   pszSavedCwd         The saved current working directory.  This is
+ *                              NULL if the CWD doesn't need changing.
+ * @param   cOrders             Number of file operation orders.
+ * @param   paOrders            The file operation orders.
+ * @param   pFileActions        The posix_spawn file actions.
+ * @param   cVerbosity          The verbosity level.
+ * @param   pPidSpawned         Where to return the PID of the spawned child
+ *                              when we're inside KMK and we're return without
+ *                              waiting.
+ * @param   pfIsChildExitCode   Where to indicate whether the return exit code
+ *                              is from the child or from our setup efforts.
+ */
+static int kRedirectDoSpawn(const char *pszExecutable, int cArgs, char **papszArgs, int fWatcomBrainDamage, char **papszEnv,
+                            const char *pszCwd, const char *pszSavedCwd, unsigned cOrders, REDIRECTORDERS *paOrders,
+#ifdef USE_POSIX_SPAWN
+                            posix_spawn_file_actions_t *pFileActions,
 #endif
-                    psz++;
-                    break;
+                            unsigned cVerbosity,
+#ifdef KMK
+                            pid_t *pPidSpawned,
+#endif
+                            KBOOL *pfIsChildExitCode)
+{
+    int     rcExit;
+    int     i;
+#ifdef _MSC_VER
+    char  **papszArgsOriginal = papszArgs;
+#endif
+    *pfIsChildExitCode = K_FALSE;
 
-                case 't':
-#ifdef O_TEXT
-                    fOpen |= O_TEXT;
+#ifdef _MSC_VER
+    /*
+     * Do MSC parameter quoting.
+     */
+    papszArgs = malloc((cArgs + 1) * sizeof(papszArgs[0]));
+    if (papszArgs)
+        memcpy(papszArgs, papszArgsOriginal, (cArgs + 1) * sizeof(papszArgs[0]));
+    else
+        return errx(9, "out of memory!");
+
+    rcExit = quote_argv(cArgs, papszArgs, fWatcomBrainDamage, 0 /*fFreeOrLeak*/);
+    if (rcExit == 0)
 #endif
-                    psz++;
-                    break;
+    {
+        /*
+         * Display what we're about to execute if we're in verbose mode.
+         */
+        if (cVerbosity > 0)
+        {
+            for (i = 0; i < cArgs; i++)
+                warnx("debug: argv[%i]=%s<eos>", i, papszArgs[i]);
+            for (i = 0; i < (int)cOrders; i++)
+                switch (paOrders[i].enmOrder)
+                {
+                    case kRedirectOrder_Close:
+                        warnx("debug: close %d\n", paOrders[i].fdTarget);
+                        break;
+                    case kRedirectOrder_Dup:
+                        warnx("debug: dup %d to %d\n", paOrders[i].fdSource, paOrders[i].fdTarget);
+                        break;
+                    case kRedirectOrder_Open:
+                        warnx("debug: open '%s' (%#x) as [%d ->] %d\n",
+                              paOrders[i].pszFilename, paOrders[i].fOpen, paOrders[i].fdSource, paOrders[i].fdTarget);
+                        break;
+                    default:
+                        warnx("error! invalid enmOrder=%d", paOrders[i].enmOrder);
+                        assert(0);
+                        break;
+                }
+            if (pszSavedCwd)
+                warnx("debug: chdir %s\n", pszCwd);
+        }
 
-                default:
-#ifdef O_BINARY
-                    fOpen |= O_BINARY;
+        /*
+         * Change working directory if so requested.
+         */
+        if (pszSavedCwd)
+        {
+            if (chdir(pszCwd) < 0)
+                rcExit = errx(10, "Failed to change directory to '%s'", pszCwd);
+        }
+        if (rcExit == 0)
+        {
+#ifndef USE_POSIX_SPAWN
+            /*
+             * Execute the file orders.
+             */
+            FILE *pWorkingStdErr = NULL;
+            rcExit = kRedirectExecFdOrders(cOrders, paOrders, &pWorkingStdErr);
+            if (rcExit == 0)
 #endif
-                    break;
+            {
+#ifdef KMK
+                /*
+                 * We're spawning from within kmk.
+                 */
+#if defined(KBUILD_OS_WINDOWS)
+                /* Windows is slightly complicated due to handles and sub_proc.c. */
+                HANDLE  hProcess = (HANDLE)_spawnvpe(_P_NOWAIT, pszExecutable, papszArgs, papszEnv);
+                kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
+                if ((intptr_t)hProcess != -1)
+                {
+                    if (process_kmk_register_redirect(hProcess, pPidSpawned) == 0)
+                    {
+                        if (cVerbosity > 0)
+                            warnx("debug: spawned %d", *pPidSpawned);
+                    }
+                    else
+                    {
+                        DWORD dwTmp;
+                        warn("sub_proc is out of slots, waiting for child...");
+                        dwTmp = WaitForSingleObject(hProcess, INFINITE);
+                        if (dwTmp != WAIT_OBJECT_0)
+                            warn("WaitForSingleObject failed: %#x\n", dwTmp);
+
+                        if (GetExitCodeProcess(hProcess, &dwTmp))
+                            rcExit = (int)dwTmp;
+                        else
+                        {
+                            warn("GetExitCodeProcess failed: %u\n", GetLastError());
+                            TerminateProcess(hProcess, 127);
+                            rcExit = 127;
+                        }
+
+                        CloseHandle(hProcess);
+                        *pPidSpawned = 0;
+                        *pfIsChildExitCode = K_TRUE;
+                    }
+                }
+                else
+                    rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
+
+# elif defined(KBUILD_OS_OS2)
+                *pPidSpawned = _spawnve(_P_NOWAIT, pszExecutable, papszArgs, papszEnv);
+                kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
+                if (*pPidSpawned != -1)
+                {
+                    if (cVerbosity > 0)
+                        warnx("debug: spawned %d", *pPidSpawned);
+                }
+                else
+                {
+                    rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
+                    *pPidSpawned = 0;
+                }
+#else
+                rcExit = posix_spawnp(pPidSpawned, pszExecutable, pFileActions, NULL /*pAttr*/, papszArgs, papszEnvVars);
+                if (rcExit == 0)
+                {
+                    if (cVerbosity > 0)
+                        warnx("debug: spawned %d", *pPidSpawned);
+                }
+                else
+                {
+                    rcExit = errx(10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
+                    *pPidSpawned = 0;
+                }
+#endif
+
+#else  /* !KMK */
+                /*
+                 * Spawning from inside the kmk_redirect executable.
+                 */
+# if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
+                errno  = 0;
+                rcExit = (int)_spawnvpe(_P_WAIT, pszExecutable, papszArgs, papszEnv);
+                kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
+                if (rcExit != -1 || errno == 0)
+                {
+                    *pfIsChildExitCode = K_TRUE;
+                    if (cVerbosity > 0)
+                        warnx("debug: exit code: %d", rcExit);
+                }
+                else
+                    rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
+
+# else
+                pid_t pidChild = 0;
+                rcExit = posix_spawnp(&pidChild, pszExecutable, pFileActions, NULL /*pAttr*/, papszArgs, papszEnvVars);
+                if (rcExit == 0)
+                {
+                    *pfIsChildExitCode = K_TRUE;
+                    if (cVerbosity > 0)
+                        warnx("debug: spawned %d", pidChild);
+
+                    /* Wait for the child. */
+                    for (;;)
+                    {
+                        pid_t pid = waitpid(pidChild, &rcExit, 0 /*block*/);
+                        if (pid == pidChild)
+                        {
+                            if (cVerbosity > 0)
+                                warnx("debug: %d exit code: %d", pidChild, rcExit);
+                            break;
+                        }
+                        if (   errno != EINTR
+#  ifdef ERESTART
+                            && errno != ERESTART
+#  endif
+                           )
+                        {
+                            rcExit = err(11, "waitpid failed");
+                            kill(pidChild, SIGKILL);
+                            break;
+                        }
+                    }
+                }
+                else
+                    rcExit = errx(10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
 
+# endif
+#endif /* !KMK */
             }
+        }
+
+        /*
+         * Restore the current directory.
+         */
+        if (pszSavedCwd)
+        {
+            if (chdir(pszSavedCwd) < 0)
+                warn("Failed to restore directory to '%s'", pszSavedCwd);
+        }
+    }
+#ifdef _MSC_VER
+    else
+        rcExit = errx(9, "quite_argv failed: %u", rcExit);
+
+    /* Restore the original argv strings, freeing the quote_argv replacements. */
+    i = cArgs;
+    while (i-- > 0)
+        if (papszArgs[i] != papszArgsOriginal[i])
+            free(papszArgs[i]);
+    free(papszArgs);
+#endif
+    return rcExit;
+}
+
+
+/**
+ * The function that does almost everything here... ugly.
+ */
+#ifdef KMK
+int kmk_builtin_redirect(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned)
+#else
+int main(int argc, char **argv, char **envp)
+#endif
+{
+    int             rcExit = 0;
+    KBOOL           fChildExitCode = K_FALSE;
+#ifdef USE_POSIX_SPAWN
+    posix_spawn_file_actions_t FileActions;
+#endif
+    unsigned        cOrders = 0;
+    REDIRECTORDERS  aOrders[32];
+
+    int             iArg;
+    const char     *pszExecutable      = NULL;
+    char          **papszEnv           = NULL;
+    unsigned        cAllocatedEnvVars;
+    unsigned        iEnvVar;
+    unsigned        cEnvVars;
+    int             fWatcomBrainDamage = 0;
+    int             cVerbosity         = 0;
+    char           *pszSavedCwd        = NULL;
+    size_t const    cbCwdBuf           = GET_PATH_MAX;
+    PATH_VAR(szCwd);
+#ifdef KBUILD_OS_OS2
+    ULONG           ulLibPath;
+    char           *apszSavedLibPaths[LIBPATHSTRICT + 1] = { NULL, NULL, NULL, NULL };
+#endif
+
+
+    g_progname = argv[0];
+
+    if (argc <= 1)
+        return usage(stderr, argv[0]);
+
+    /*
+     * Create default program environment.
+     */
+#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
+    if (getcwd_fs(szCwd, cbCwdBuf) != NULL)
+#else
+    if (getcwd(szCwd, cbCwdBuf) != NULL)
+#endif
+    { /* likely */ }
+    else
+        return err(9, "getcwd failed");
+
+#if defined(KMK)
+    /* We get it from kmk and just count it:  */
+    papszEnv = pChild->environment;
+    if (!papszEnv)
+        pChild->environment = papszEnv = target_environment(pChild->file);
+    cEnvVars = 0;
+    while (papszEnv[cEnvVars] != NULL)
+        cEnvVars++;
+    cAllocatedEnvVars = cEnvVars;
+#else
+    /* We make a copy and we manage ourselves: */
+    cEnvVars = 0;
+    while (envp[cEnvVars] != NULL)
+        cEnvVars++;
+
+    cAllocatedEnvVars = cEnvVars + 4;
+    papszEnv = malloc((cAllocatedEnvVars + 1) * sizeof(papszEnv));
+    if (!papszEnv)
+        return errx(9, "out of memory!");
+
+    iEnvVar = cEnvVars;
+    papszEnv[iEnvVar] = NULL;
+    while (iEnvVar-- > 0)
+    {
+        papszEnv[iEnvVar] = strdup(envp[iEnvVar]);
+        if (!papszEnv[iEnvVar])
+        {
+            while (iEnvVar-- > 0)
+                free(papszEnv[iEnvVar]);
+            free(papszEnv);
+            return errx(9, "out of memory!");
+        }
+    }
+#endif
 
-            /* convert to file descriptor number */
-            switch (*psz)
+#ifdef USE_POSIX_SPAWN
+    /*
+     * Init posix attributes.
+     */
+    rcExit = posix_spawn_file_actions_init(&FileActions);
+    if (rcExit != 0)
+        rcExit = errx(9, "posix_spawn_file_actions_init failed: %s", strerror(rcExit));
+#endif
+
+    /*
+     * Parse arguments.
+     */
+    for (iArg = 1; rcExit == 0 && iArg < argc; iArg++)
+    {
+        char *pszArg = argv[iArg];
+        if (*pszArg == '-')
+        {
+            int         fd;
+            char        chOpt;
+            const char *pszValue;
+
+            chOpt = *++pszArg;
+            pszArg++;
+            if (chOpt == '-')
             {
-                case 'i':
-                    fd = 0;
-                    psz++;
+                /* '--' indicates where the bits to execute start. */
+                if (*pszArg == '\0')
+                {
+                    iArg++;
                     break;
+                }
+
+                if (   strcmp(pszArg, "wcc-brain-damage") == 0
+                    || strcmp(pszArg, "watcom-brain-damage") == 0)
+                {
+                    fWatcomBrainDamage = 1;
+                    continue;
+                }
 
-                case 'o':
-                    fd = 1;
-                    psz++;
+                /* convert to short. */
+                if (strcmp(pszArg, "help") == 0)
+                    chOpt = 'h';
+                else if (strcmp(pszArg, "version") == 0)
+                    chOpt = 'V';
+                else if (   strcmp(pszArg, "set") == 0
+                         || strcmp(pszArg, "env") == 0)
+                    chOpt = 'E';
+                else if (strcmp(pszArg, "unset") == 0)
+                    chOpt = 'U';
+                else if (   strcmp(pszArg, "zap-env") == 0
+                         || strcmp(pszArg, "ignore-environment") == 0 /* GNU env compatibility. */ )
+                    chOpt = 'Z';
+                else if (strcmp(pszArg, "chdir") == 0)
+                    chOpt = 'C';
+                else if (strcmp(pszArg, "close") == 0)
+                    chOpt = 'c';
+                else if (strcmp(pszArg, "verbose") == 0)
+                    chOpt = 'v';
+                else
+                {
+                    errx(2, "Unknown option: '%s'", pszArg - 2);
+                    rcExit = usage(stderr, argv[0]);
                     break;
+                }
+                pszArg = "";
+            }
+
+            /*
+             * Deal with the obligatory help and version switches first to get them out of the way.
+             */
+            if (chOpt == 'h')
+            {
+                usage(stdout, argv[0]);
+                rcExit = -1;
+                break;
+            }
+            if (chOpt == 'V')
+            {
+                kbuild_version(argv[0]);
+                rcExit = -1;
+                break;
+            }
 
-                case 'e':
-                    fd = 2;
-                    psz++;
+            /*
+             * Get option value first, if the option takes one.
+             */
+            if (   chOpt == 'E'
+                || chOpt == 'U'
+                || chOpt == 'C'
+                || chOpt == 'c'
+                || chOpt == 'd'
+                || chOpt == 'e')
+            {
+                if (*pszArg != '\0')
+                    pszValue = pszArg + (*pszArg == ':' || *pszArg == '=');
+                else if (++iArg < argc)
+                    pszValue = argv[iArg];
+                else
+                {
+                    errx(2, "syntax error: Option -%c requires a value!", chOpt);
+                    rcExit = usage(stderr, argv[0]);
                     break;
+                }
+            }
+            else
+                pszValue = NULL;
 
-                case '0':
-                    if (!psz[1])
+            /*
+             * Environment switch?
+             */
+            if (chOpt == 'E')
+            {
+                const char *pchEqual = strchr(pszValue, '=');
+#ifdef KBUILD_OS_OS2
+                if (   strncmp(pszValue, TUPLE("BEGINLIBPATH=")) == 0
+                    || strncmp(pszValue, TUPLE("ENDLIBPATH=")) == 0
+                    || strncmp(pszValue, TUPLE("LIBPATHSTRICT=")) == 0)
+                {
+                    ULONG   ulVar  = *pszValue == 'B' ? BEGIN_LIBPATH
+                                   : *pszValue == 'E' ? END_LIBPATH
+                                   :                    LIBPATHSTRICT;
+                    APIRET  rc;
+                    if (apszSavedLibPaths[ulVar] == NULL)
                     {
-                        fd = 0;
-                        psz++;
-                        break;
+                        /* The max length is supposed to be 1024 bytes. */
+                        apszSavedLibPaths[ulVar] = calloc(1024 * 2);
+                        if (apszSavedLibPaths[ulVar])
+                        {
+                            rc = DosQueryExtLIBPATH(apszSavedLibPaths[ulVar], ulVar);
+                            if (rc)
+                            {
+                                rcExit = errx(9, "DosQueryExtLIBPATH(,%u) failed: %lu", ulVar, rc);
+                                free(apszSavedLibPaths[ulVar]);
+                                apszSavedLibPaths[ulVar] = NULL;
+                            }
+                        }
+                        else
+                            rcExit = errx(9, "out of memory!");
                     }
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7':
-                case '8':
-                case '9':
-                    fd = (int)strtol(psz, &psz, 0);
-                    if (!fd)
+                    if (rcExit == 0)
                     {
-                        fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
-                        return 1;
+                        rc = DosSetExtLIBPATH(pchEqual + 1, ulVar);
+                        if (rc)
+                            rcExit = errx(9, "error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu",
+                                          pchEqual, pchEqual - pszValue, pchEqual + 1, ulVar, rc);
+                    }
+                    continue;
+                }
+#endif /* KBUILD_OS_OS2 */
 
+                /* We differ from kSubmit here and use putenv sematics. */
+                if (pchEqual)
+                {
+                    if (pchEqual[1] != '\0')
+                    {
+                        rcExit = kBuiltinOptEnvSet(&papszEnv, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+#ifdef KMK
+                        pChild->environment = papszEnv;
+#endif
                     }
-                    if (fd < 0)
+                    else
                     {
-                        fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
-                        return 1;
+                        char *pszCopy = strdup(pszValue);
+                        if (pszCopy)
+                        {
+                            pszCopy[pchEqual - pszValue] = '\0';
+                            rcExit = kBuiltinOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszCopy);
+                            free(pszCopy);
+                        }
+                        else
+                            rcExit = errx(1, "out of memory!");
                     }
-                    break;
+                    continue;
+                }
+                /* Simple unset. */
+                chOpt = 'U';
+            }
 
-                /*
-                 * Invalid argument.
-                 */
-                default:
-                    fprintf(pStdErr, "%s: error: failed to convert '%s' ('%s') to a file descriptor\n", name(argv[0]), psz, argv[i]);
-                    return 1;
+            /*
+             * Unset environment variable.
+             */
+            if (chOpt == 'U')
+            {
+#ifdef KBUILD_OS_OS2
+                if (   strcmp(pszValue, "BEGINLIBPATH") == 0
+                    || strcmp(pszValue, "ENDLIBPATH") == 0
+                    || strcmp(pszValue, "LIBPATHSTRICT") == 0)
+                    rcExit = errx(2, "error: '%s' cannot be unset, only set to an empty value using -E/--set.", pszValue);
+                else
+#endif
+                    rcExit = kBuiltinOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszValue);
+                continue;
             }
 
             /*
-             * Check for the filename.
+             * Zap environment switch?
              */
-            if (*psz)
+            if (   chOpt == 'Z'
+                || chOpt == 'i' /* GNU env compatibility. */ )
             {
-                if (*psz != ':' && *psz != '=')
-                {
-                    fprintf(pStdErr, "%s: syntax error: characters following the file descriptor: '%s' ('%s')\n", name(argv[0]), psz, argv[i]);
-                    return 1;
-                }
-                psz++;
+                for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
+                    free(papszEnv[iEnvVar]);
+                papszEnv[0] = NULL;
+                cEnvVars = 0;
+                continue;
             }
-            else
+
+            /*
+             * Change directory switch?
+             */
+            if (chOpt == 'C')
             {
-                i++;
-                if (i >= argc)
-                {
-                    fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
-                    return 1;
-                }
-                psz = argv[i];
+                if (pszSavedCwd == NULL)
+                    pszSavedCwd = strdup(szCwd);
+                if (pszSavedCwd)
+                    rcExit = kBuiltinOptChDir(szCwd, cbCwdBuf, pszValue);
+                else
+                    rcExit = err(9, "out of memory!");
+                continue;
             }
 
+
             /*
-             * Setup the redirection.
+             * Verbose operation switch?
              */
-            if (fd == fileno(pStdErr))
+            if (chOpt == 'v')
+            {
+                cVerbosity++;
+                continue;
+            }
+
+            /*
+             * Executable image other than the first argument following '--'.
+             */
+            if (chOpt == 'e')
+            {
+                pszExecutable = pszValue;
+                continue;
+            }
+
+            /*
+             * Okay, it is some file descriptor opearation.  Make sure we've got room for it.
+             */
+            if (cOrders + 1 < K_ELEMENTS(aOrders))
+            {
+                aOrders[cOrders].fdTarget         = -1;
+                aOrders[cOrders].fdSource         = -1;
+                aOrders[cOrders].fOpen            = 0;
+                aOrders[cOrders].fRemoveOnFailure = 0;
+                aOrders[cOrders].pszFilename      = NULL;
+#ifndef USE_POSIX_SPAWN
+                aOrders[cOrders].fdSaved          = -1;
+#endif
+            }
+            else
+            {
+                rcExit = errx(2, "error: too many file actions (max: %d)", K_ELEMENTS(aOrders));
+                break;
+            }
+
+            if (chOpt == 'c')
             {
                 /*
-                 * Move stderr to a new location, making it close on exec.
-                 * If pStdOut has already teamed up with pStdErr, update it too.
+                 * Close the specified file descriptor (no stderr/out/in aliases).
                  */
-                FILE *pNew;
-                fdOpened = dup(fileno(pStdErr));
-                if (fdOpened == -1)
+                char *pszTmp;
+                fd = (int)strtol(pszValue, &pszTmp, 0);
+                if (pszTmp == pszValue || *pszTmp != '\0')
+                    rcExit = errx(2, "error: failed to convert '%s' to a number", pszValue);
+                else if (fd < 0)
+                    rcExit = errx(2, "error: negative fd %d (%s)", fd, pszValue);
+                else
                 {
-                    fprintf(pStdErr, "%s: error: failed to dup stderr (%d): %s\n", name(argv[0]), fileno(pStdErr), strerror(errno));
-                    return 1;
+                    aOrders[cOrders].enmOrder = kRedirectOrder_Close;
+                    aOrders[cOrders].fdTarget = fd;
+                    cOrders++;
+#ifdef USE_POSIX_SPAWN
+                    rcExit = posix_spawn_file_actions_addclose(&FileActions, fd);
+                    if (rcExit != 0)
+                        rcExit = errx(2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
+#endif
                 }
-#ifdef _MSC_VER
-                /** @todo figure out how to make the handle close-on-exec. We'll simply close it for now.
-                 * SetHandleInformation + set FNOINHERIT in CRT.
+            }
+            else if (chOpt == 'd')
+            {
+                /*
+                 * Duplicate file handle.  Value is fdTarget=fdSource
                  */
-#else
-                if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) == -1)
+                char *pszEqual;
+                fd = (int)strtol(pszValue, &pszEqual, 0);
+                if (pszEqual == pszValue)
+                    rcExit = errx(2, "error: failed to convert target descriptor of '-d %s' to a number", pszValue);
+                else if (fd < 0)
+                    rcExit = errx(2, "error: negative target descriptor %d ('-d %s')", fd, pszValue);
+                else if (*pszEqual != '=')
+                    rcExit = errx(2, "syntax error: expected '=' to follow target descriptor: '-d %s'", pszValue);
+                else
                 {
-                    fprintf(pStdErr, "%s: error: failed to make stderr (%d) close-on-exec: %s\n", name(argv[0]), fdOpened, strerror(errno));
-                    return 1;
-                }
+                    char *pszEnd;
+                    int fdSource = (int)strtol(++pszEqual, &pszEnd, 0);
+                    if (pszEnd == pszEqual || *pszEnd != '\0')
+                        rcExit = errx(2, "error: failed to convert source descriptor of '-d %s' to a number", pszValue);
+                    else if (fdSource < 0)
+                        rcExit = errx(2, "error: negative source descriptor %d ('-d %s')", fdSource, pszValue);
+                    else
+                    {
+                        aOrders[cOrders].enmOrder = kRedirectOrder_Dup;
+                        aOrders[cOrders].fdTarget = fd;
+                        aOrders[cOrders].fdSource = fdSource;
+                        cOrders++;
+#ifdef USE_POSIX_SPAWN
+                        rcExit = posix_spawn_file_actions_adddup2(&FileActions, fdSource, fd);
+                        if (rcExit != 0)
+                            rcExit = errx(2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
 #endif
+                    }
+                }
+            }
+            else
+            {
+                /*
+                 * Open file as a given file descriptor.
+                 */
+                int fdOpened;
+                int fOpen;
 
-                pNew = fdopen(fdOpened, "w");
-                if (!pNew)
+                /* mode */
+                switch (chOpt)
                 {
-                    fprintf(pStdErr, "%s: error: failed to fdopen the new stderr (%d): %s\n", name(argv[0]), fdOpened, strerror(errno));
-                    return 1;
+                    case 'r':
+                        chOpt = *pszArg++;
+                        if (chOpt == '+')
+                        {
+                            fOpen = O_RDWR;
+                            chOpt = *pszArg++;
+                        }
+                        else
+                            fOpen = O_RDONLY;
+                        break;
+
+                    case 'w':
+                        chOpt = *pszArg++;
+                        if (chOpt == '+')
+                        {
+                            fOpen = O_RDWR | O_CREAT | O_TRUNC;
+                            chOpt = *pszArg++;
+                        }
+                        else
+                            fOpen = O_WRONLY | O_CREAT | O_TRUNC;
+                        aOrders[cOrders].fRemoveOnFailure = 1;
+                        break;
+
+                    case 'a':
+                        chOpt = *pszArg++;
+                        if (chOpt == '+')
+                        {
+                            fOpen = O_RDWR | O_CREAT | O_APPEND;
+                            chOpt = *pszArg++;
+                        }
+                        else
+                            fOpen = O_WRONLY | O_CREAT | O_APPEND;
+                        break;
+
+                    case 'i': /* make sure stdin is read-only. */
+                        fOpen = O_RDONLY;
+                        break;
+
+                    case '+':
+                        rcExit = errx(2, "syntax error: Unexpected '+' in '%s'", argv[iArg]);
+                        continue;
+
+                    default:
+                        fOpen = O_RDWR | O_CREAT | O_TRUNC;
+                        aOrders[cOrders].fRemoveOnFailure = 1;
+                        break;
                 }
-                if (pStdOut == pStdErr)
-                    pStdOut = pNew;
-                pStdErr = pNew;
-            }
-            else if (fd == 1 && pStdOut != pStdErr)
-                pStdOut = pStdErr;
 
-            /*
-             * Close and open the new file descriptor.
-             */
-            safeCloseFd(fd);
-#if defined(_MSC_VER)
-            if (!strcmp(psz, "/dev/null"))
-                psz = (char *)"nul";
+                /* binary / text modifiers */
+                switch (chOpt)
+                {
+                    case 'b':
+                        chOpt = *pszArg++;
+                    default:
+#ifdef O_BINARY
+                        fOpen |= O_BINARY;
+#elif defined(_O_BINARY)
+                        fOpen |= _O_BINARY;
 #endif
-            fdOpened = open(psz, fOpen, 0666);
-            if (fdOpened == -1)
-            {
-                fprintf(pStdErr, "%s: error: failed to open '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
-                return 1;
-            }
-            if (fdOpened != fd)
-            {
-                /* move it (dup2 returns 0 on MSC). */
-                if (dup2(fdOpened, fd) == -1)
+                        break;
+
+                    case 't':
+#ifdef O_TEXT
+                        fOpen |= O_TEXT;
+#elif defined(_O_TEXT)
+                        fOpen |= _O_TEXT;
+#endif
+                        chOpt = *pszArg++;
+                        break;
+
+                }
+
+                /* convert to file descriptor number */
+                switch (chOpt)
                 {
-                    fprintf(pStdErr, "%s: error: failed to dup '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
-                    return 1;
+                    case 'i':
+                        fd = 0;
+                        break;
+
+                    case 'o':
+                        fd = 1;
+                        break;
+
+                    case 'e':
+                        fd = 2;
+                        break;
+
+                    case '0':
+                        if (*pszArg == '\0')
+                        {
+                            fd = 0;
+                            break;
+                        }
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                    case '8':
+                    case '9':
+                        pszValue = pszArg - 1;
+                        fd = (int)strtol(pszValue, &pszArg, 0);
+                        if (pszArg == pszValue)
+                            rcExit = errx(2, "error: failed to convert '%s' to a number", argv[iArg]);
+                        else if (fd < 0)
+                            rcExit = errx(2, "error: negative fd %d (%s)", fd, argv[iArg]);
+                        else
+                            break;
+                        continue;
+
+                    /*
+                     * Invalid argument.
+                     */
+                    default:
+                        rcExit = errx(2, "error: failed to convert '%s' ('%s') to a file descriptor", pszArg, argv[iArg]);
+                        continue;
+                }
+
+                /*
+                 * Check for the filename.
+                 */
+                if (*pszArg != '\0')
+                {
+                    if (*pszArg != ':' && *pszArg != '=')
+                    {
+                        rcExit = errx(2, "syntax error: characters following the file descriptor: '%s' ('%s')",
+                                      pszArg, argv[iArg]);
+                        break;
+                    }
+                    pszArg++;
+                }
+                else if (++iArg < argc)
+                    pszArg = argv[iArg];
+                else
+                {
+                    rcExit = errx(2, "syntax error: missing filename argument.");
+                    break;
+                }
+
+                /*
+                 * Open the file.  We could've used posix_spawn_file_actions_addopen here,
+                 * but that means complicated error reporting.  So, since we need to do
+                 * this for windows anyway, just do it the same way everywhere.
+                 */
+                fdOpened = kRedirectOpenWithoutConflict(pszArg, fOpen, 0666, cOrders, aOrders,
+                                                        aOrders[cOrders].fRemoveOnFailure, fd);
+                if (fdOpened >= 0)
+                {
+                    aOrders[cOrders].enmOrder    = kRedirectOrder_Open;
+                    aOrders[cOrders].fdTarget    = fd;
+                    aOrders[cOrders].fdSource    = fdOpened;
+                    aOrders[cOrders].fOpen       = fOpen;
+                    aOrders[cOrders].pszFilename = pszArg;
+                    cOrders++;
+
+#ifdef USE_POSIX_SPAWN
+                    if (fdOpened != fdSource)
+                    {
+                        rcExit = posix_spawn_file_actions_adddup2(&FileActions, fdOpened, fd);
+                        if (rcExit != 0)
+                            rcExit = err(9, "posix_spawn_file_actions_adddup2(,%d [%s], %d) failed: %s",
+                                         fdOpened, fd, pszArg, strerror(rcExit));
+                    }
+#endif
                 }
-                close(fdOpened);
+                else
+                    rcExit = 9;
             }
         }
         else
         {
-            fprintf(pStdErr, "%s: syntax error: Invalid argument '%s'.\n", name(argv[0]), argv[i]);
-            return usage(pStdErr, name(argv[0]));
+            errx(2, "syntax error: Invalid argument '%s'.", argv[iArg]);
+            rcExit = usage(stderr, argv[0]);
         }
     }
+    if (!pszExecutable)
+        pszExecutable = argv[iArg];
 
     /*
      * Make sure there's something to execute.
      */
-    if (i >= argc)
+    if (rcExit == 0 && iArg < argc)
     {
-        fprintf(pStdErr, "%s: syntax error: nothing to execute!\n", name(argv[0]));
-        return usage(pStdErr, name(argv[0]));
+        /*
+         * Do the spawning in a separate function (main is far to large as it is by now).
+         */
+        rcExit = kRedirectDoSpawn(pszExecutable, argc - iArg, &argv[iArg], fWatcomBrainDamage, papszEnv, szCwd, pszSavedCwd,
+#ifdef USE_POSIX_SPAWN
+                                  cOrders, aOrders, &FileActions, cVerbosity,
+#else
+                                  cOrders, aOrders, cVerbosity,
+#endif
+#ifdef KMK
+                                  pPidSpawned,
+#endif
+                                  &fChildExitCode);
     }
-
-#if defined(_MSC_VER)
-    if (fileno(pStdErr) != 2) /* no close-on-exec flag on windows */
+    else if (rcExit == 0)
     {
-        fclose(pStdErr);
-        pStdErr = NULL;
+        errx(2, "syntax error: nothing to execute!");
+        rcExit = usage(stderr, argv[0]);
     }
+    /* Help and version sets rcExit to -1. Change it to zero. */
+    else if (rcExit == -1)
+        rcExit = 0;
 
-    /* MSC is a PITA since it refuses to quote the arguments... */
-    quote_argv(argc - i, &argv[i], fWatcomBrainDamage, 0 /*fFreeOrLeak*/);
-    if (g_cVerbosity > 0)
-        for (j = i; j < argc; j++)
-            fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", j - i, argv[j]);
-    rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
-    if (rc == -1 && pStdErr)
-    {
-        fprintf(pStdErr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
-        rc = 1;
-    }
-    return rc;
-#else
-    if (g_cVerbosity > 0)
-        for (j = i; j < argc; j++)
-            fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", j - i, argv[j]);
-    execvp(argv[i], &argv[i]);
-    fprintf(pStdErr, "%s: error: _execvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
-    return 1;
+    /*
+     * Cleanup.
+     */
+    if (pszSavedCwd)
+        free(pszSavedCwd);
+    kRedirectCleanupFdOrders(cOrders, aOrders, rcExit != 0 && !fChildExitCode);
+#ifdef USE_POSIX_SPAWN
+    posix_spawn_file_actions_destroy(&FileActions);
 #endif
+#ifndef KMK
+    iEnvVar = cEnvVars;
+    while (iEnvVar-- > 0)
+        free(papszEnv[iEnvVar]);
+    free(papszEnv);
+#endif
+#ifdef KBUILD_OS_OS2
+    for (ulLibPath = 0; ulLibPath < K_ELEMENTS(apszSavedLibPaths); ulLibPath++)
+        if (apszSavedLibPaths[ulLibPath] != NULL)
+        {
+            APIRET rc = DosSetExtLIBPATH(apszSavedLibPaths[ulLibPath], ulLibPath);
+            if (rc != 0)
+                warnx("DosSetExtLIBPATH('%s',%u) failed with %u when restoring the original values!",
+                      apszSavedLibPaths[ulLibPath], ulLibPath, rc);
+            free(apszSavedLibPaths[ulLibPath])
+        }
+#endif
+
+    return rcExit;
 }
 
diff --git a/src/kmk/kmkbuiltin/rm.c b/src/kmk/kmkbuiltin/rm.c
index 17b7ca2..986f991 100644
--- a/src/kmk/kmkbuiltin/rm.c
+++ b/src/kmk/kmkbuiltin/rm.c
@@ -388,14 +388,28 @@ rm_tree(char **argv)
 			switch (p->fts_info) {
 			case FTS_DP:
 			case FTS_DNR:
+#ifdef KBUILD_OS_WINDOWS
+				if (p->fts_parent->fts_dirfd != NT_FTS_INVALID_HANDLE_VALUE) {
+				    rval = birdUnlinkForcedEx(p->fts_parent->fts_dirfd, p->fts_name);
+				} else {
+				    rval = birdUnlinkForced(p->fts_accpath);
+				}
+#else
 				rval = rmdir(p->fts_accpath);
+#endif
 				if (rval == 0 || (fflag && errno == ENOENT)) {
 					if (rval == 0 && vflag)
 						(void)printf("%s\n",
 						    p->fts_path);
+#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
+					if (rval == 0) {
+					    extern int dir_cache_deleted_directory(const char *pszDir);
+					    dir_cache_deleted_directory(p->fts_accpath);
+					}
+#endif
 					continue;
 				}
-				operation = "mkdir";
+				operation = "rmdir";
 				break;
 
 #ifdef FTS_W
@@ -424,7 +438,11 @@ rm_tree(char **argv)
 					if (!rm_overwrite(p->fts_accpath, NULL))
 						continue;
 #ifdef KBUILD_OS_WINDOWS
-				rval = birdUnlinkForcedFast(p->fts_accpath);
+				if (p->fts_parent->fts_dirfd != NT_FTS_INVALID_HANDLE_VALUE) {
+				    rval = birdUnlinkForcedFastEx(p->fts_parent->fts_dirfd, p->fts_name);
+				} else {
+				    rval = birdUnlinkForcedFast(p->fts_accpath);
+				}
 #else
 				rval = unlink(p->fts_accpath);
 #endif
diff --git a/src/kmk/kmkbuiltin/rmdir.c b/src/kmk/kmkbuiltin/rmdir.c
index 34771dd..52821be 100644
--- a/src/kmk/kmkbuiltin/rmdir.c
+++ b/src/kmk/kmkbuiltin/rmdir.c
@@ -59,6 +59,9 @@ __FBSDID("$FreeBSD: src/bin/rmdir/rmdir.c,v 1.20 2005/01/26 06:51:28 ssouhlal Ex
 #ifdef _MSC_VER
 # include "mscfakes.h"
 #endif
+#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
+extern int dir_cache_deleted_directory(const char *pszDir);
+#endif
 
 static int rm_path(char *);
 static int usage(FILE *);
@@ -134,8 +137,13 @@ kmk_builtin_rmdir(int argc, char *argv[], char **envp)
 			if (!ignore_fail_on_not_exist || errno != ENOENT)
 				continue;
 			/* (only ignored doesn't exist errors fall thru) */
-		} else if (vflag) {
-			printf("%s\n", *argv);
+		} else {
+#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
+			dir_cache_deleted_directory(*argv);
+#endif
+			if (vflag) {
+				printf("%s\n", *argv);
+			}
 		}
 		if (pflag)
 			errors |= rm_path(*argv);
@@ -177,13 +185,19 @@ rm_path(char *path)
 #endif
 
 		if (rmdir(path) < 0) {
-			if (ignore_fail_on_non_empty && (errno == ENOTEMPTY || errno == EPERM || errno == EACCES || errno == EINVAL || errno == EEXIST))
+			if (   ignore_fail_on_non_empty
+			    && (   errno == ENOTEMPTY || errno == EPERM || errno == EACCES || errno == EINVAL || errno == EEXIST))
 				break;
 			if (!ignore_fail_on_not_exist || errno != ENOENT) {
 				warn("rmdir: %s", path);
 				return (1);
 			}
 		}
+#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
+		else {
+			dir_cache_deleted_directory(path);
+		}
+#endif
 		if (vflag)
 			printf("%s\n", path);
 	}
diff --git a/src/kmk/main.c b/src/kmk/main.c
index b648f42..7bb2437 100644
--- a/src/kmk/main.c
+++ b/src/kmk/main.c
@@ -89,6 +89,7 @@ void verify_file_data_base (void);
 
 #ifdef CONFIG_WITH_PRINT_STATS_SWITCH
 void print_variable_stats (void);
+void print_dir_stats (void);
 void print_file_stats (void);
 #endif
 
@@ -915,6 +916,7 @@ set_make_priority_and_affinity (void)
 
 
 #ifdef WINDOWS32
+# ifndef KMK
 /*
  * HANDLE runtime exceptions by avoiding a requestor on the GUI. Capture
  * exception and print it to stderr instead.
@@ -989,6 +991,7 @@ handle_runtime_exceptions( struct _EXCEPTION_POINTERS *exinfo )
   return (255); /* not reached */
 #endif
 }
+# endif /* !KMK */
 
 /*
  * On WIN32 systems we don't have the luxury of a /bin directory that
@@ -1231,16 +1234,33 @@ get_online_cpu_count(void)
 {
 # ifdef WINDOWS32
     /* Windows: Count the active CPUs. */
-    int cpus, i;
-    SYSTEM_INFO si;
-    GetSystemInfo(&si);
-    for (i = cpus = 0; i < sizeof(si.dwActiveProcessorMask) * 8; i++)
+    int cpus;
+
+    /* Process groups (W7+). */
+    typedef DWORD (WINAPI *PFNGETACTIVEPROCESSORCOUNT)(DWORD);
+    PFNGETACTIVEPROCESSORCOUNT pfnGetActiveProcessorCount;
+    pfnGetActiveProcessorCount = (PFNGETACTIVEPROCESSORCOUNT)GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
+                                                                            "GetActiveProcessorCount");
+    if (pfnGetActiveProcessorCount)
+      cpus = pfnGetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
+    /* Legacy (<= Vista). */
+    else
       {
-        if (si.dwActiveProcessorMask & 1)
-          cpus++;
-        si.dwActiveProcessorMask >>= 1;
+        int i;
+        SYSTEM_INFO si;
+        GetSystemInfo(&si);
+        for (i = cpus = 0; i < sizeof(si.dwActiveProcessorMask) * 8; i++)
+          {
+            if (si.dwActiveProcessorMask & 1)
+              cpus++;
+            si.dwActiveProcessorMask >>= 1;
+          }
       }
-    return cpus ? cpus : 1;
+    if (!cpus)
+      cpus = 1;
+    if (cpus > 64)
+      cpus = 64; /* (wait for multiple objects limit) */
+    return cpus;
 
 # elif defined(__OS2__)
     /* OS/2: Count the active CPUs. */
@@ -1376,7 +1396,9 @@ main (int argc, char **argv, char **envp)
   char *windows32_path = NULL;
 
 # ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */
+#  ifndef KMK /* Don't want none of this crap. */
   SetUnhandledExceptionFilter(handle_runtime_exceptions);
+#  endif
 # endif /* !ELECTRIC_HEAP */
 
   /* start off assuming we have no shell */
@@ -3858,6 +3880,7 @@ print_stats ()
   /* Make stuff: */
   print_variable_stats ();
   print_file_stats ();
+  print_dir_stats ();
 # ifdef KMK
   print_kbuild_define_stats ();
 # endif
diff --git a/src/kmk/make.h b/src/kmk/make.h
index 1903299..982cd0c 100644
--- a/src/kmk/make.h
+++ b/src/kmk/make.h
@@ -983,6 +983,7 @@ extern void dir_cache_invalid_after_job (void);
 extern void dir_cache_invalid_all (void);
 extern void dir_cache_invalid_missing (void);
 extern int dir_cache_volatile_dir (const char *dir);
+extern int dir_cache_deleted_directory(const char *pszDir);
 # endif
 #endif
 
diff --git a/src/kmk/w32/include/sub_proc.h b/src/kmk/w32/include/sub_proc.h
index 4876e51..0cba3f4 100644
--- a/src/kmk/w32/include/sub_proc.h
+++ b/src/kmk/w32/include/sub_proc.h
@@ -49,6 +49,7 @@ EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal));
 EXTERN_DECL(int process_used_slots, (VOID_DECL));
 #ifdef KMK
 EXTERN_DECL(int process_kmk_register_submit, (HANDLE hEvent, intptr_t clue, pid_t *pPid));
+EXTERN_DECL(int process_kmk_register_redirect, (HANDLE hProcess, pid_t *pPid));
 #endif
 
 /* support routines */
diff --git a/src/kmk/w32/subproc/sub_proc.c b/src/kmk/w32/subproc/sub_proc.c
index 695589f..f2e9b49 100644
--- a/src/kmk/w32/subproc/sub_proc.c
+++ b/src/kmk/w32/subproc/sub_proc.c
@@ -198,6 +198,7 @@ process_register(HANDLE proc)
 }
 
 #ifdef KMK
+
 /**
  * Interface used by kmkbuiltin/kSubmit.c to register stuff going down in a
  * worker process.
@@ -222,7 +223,30 @@ process_kmk_register_submit(HANDLE hEvent, intptr_t clue, pid_t *pPid)
 	}
 	return -1;
 }
-#endif
+
+/**
+ * Interface used by kmkbuiltin/kRedirect.c to register a spawned process.
+ *
+ * @returns 0 on success, -1 if there are too many sub-processes already.
+ * @param   hProcess            The process handle.
+ * @param   pPid                Where to return the pid that job.c expects.
+ */
+int
+process_kmk_register_redirect(HANDLE hProcess, pid_t *pPid)
+{
+	if (proc_index < MAXIMUM_WAIT_OBJECTS) {
+		sub_process *pSubProc = (sub_process *)xcalloc(sizeof(*pSubProc));
+		pSubProc->enmType = kRegular;
+		pSubProc->pid     = (intptr_t)hProcess;
+
+		proc_array[proc_index++] = pSubProc;
+		*pPid = (intptr_t)pSubProc;
+		return 0;
+	}
+	return -1;
+}
+
+#endif /* KMK */
 
 /*
  * Return the number of processes that we are still waiting for.
diff --git a/src/lib/Makefile.kmk b/src/lib/Makefile.kmk
index b5833c2..0cd8307 100644
--- a/src/lib/Makefile.kmk
+++ b/src/lib/Makefile.kmk
@@ -1,10 +1,10 @@
-# $Id: Makefile.kmk 2906 2016-09-09 22:15:57Z bird $
+# $Id: Makefile.kmk 2994 2016-11-01 22:41:41Z bird $
 ## @file
 # Sub-makefile for various libraries and stuff.
 #
 
 #
-# Copyright (c) 2006-2013 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+# Copyright (c) 2006-2016 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
 #
 # This file is part of kBuild.
 #
@@ -52,6 +52,7 @@ kUtil_SOURCES.win = \
        nt/ntdir.c \
        nt/ntstat.c \
        nt/ntunlink.c \
+       nt/fts-nt.c \
        nt/kFsCache.c \
        kStuff/kHlp/CRT/kHlpCRTString.cpp \
        kStuff/kHlp/CRT/kHlpCRTAlloc.cpp
@@ -79,5 +80,11 @@ tstNtStat_SOURCES = nt/tstNtStat.c
 tstNtStat_LIBS = $(LIB_KUTIL)
 tstNtStat_NOINST = 1
 
+PROGRAMS.win += tstNtFts
+tstNtFts_TEMPLATE = BIN
+tstNtFts_SOURCES = nt/tstNtFts.c nt/fts-nt.c
+tstNtFts_LIBS = $(LIB_KUTIL)
+tstNtFts_NOINST = 1
+
 include $(FILE_KBUILD_SUB_FOOTER)
 
diff --git a/src/lib/kDep.c b/src/lib/kDep.c
index da7a0dd..186c20c 100644
--- a/src/lib/kDep.c
+++ b/src/lib/kDep.c
@@ -1,4 +1,4 @@
-/* $Id: kDep.c 2886 2016-09-06 14:31:46Z bird $ */
+/* $Id: kDep.c 2955 2016-09-21 19:05:53Z bird $ */
 /** @file
  * kDep - Common Dependency Managemnt Code.
  */
@@ -58,6 +58,10 @@
 
 #include "kDep.h"
 
+#ifdef KWORKER
+extern int kwFsPathExists(const char *pszPath);
+#endif
+
 
 /*******************************************************************************
 *   Global Variables                                                           *
@@ -182,13 +186,14 @@ static void fixcase(char *pszFilename)
 /**
  * 'Optimizes' and corrects the dependencies.
  */
-void depOptimize(int fFixCase, int fQuiet)
+void depOptimize(int fFixCase, int fQuiet, const char *pszIgnoredExt)
 {
     /*
      * Walk the list correct the names and re-insert them.
      */
-    PDEP pDepOrg = g_pDeps;
-    PDEP pDep = g_pDeps;
+    size_t  cchIgnoredExt = pszIgnoredExt ? strlen(pszIgnoredExt) : 0;
+    PDEP    pDepOrg = g_pDeps;
+    PDEP    pDep = g_pDeps;
     g_pDeps = NULL;
     for (; pDep; pDep = pDep->pNext)
     {
@@ -198,7 +203,7 @@ void depOptimize(int fFixCase, int fQuiet)
         char        szFilename[PATH_MAX + 1];
 #endif
         char       *pszFilename;
-#ifndef KMK
+#if !defined(KWORKER) && !defined(KMK)
         struct stat s;
 #endif
 
@@ -210,6 +215,14 @@ void depOptimize(int fFixCase, int fQuiet)
             continue;
         pszFilename = pDep->szFilename;
 
+        /*
+         * Skip pszIgnoredExt if given.
+         */
+        if (   pszIgnoredExt
+            && pDep->cchFilename > cchIgnoredExt
+            && memcmp(&pDep->szFilename[pDep->cchFilename - cchIgnoredExt], pszIgnoredExt, cchIgnoredExt) == 0)
+            continue;
+
 #if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS
         /*
          * Skip any drive letters from compilers running in wine.
@@ -238,7 +251,9 @@ void depOptimize(int fFixCase, int fQuiet)
         /*
          * Check that the file exists before we start depending on it.
          */
-#ifdef KMK
+#ifdef KWORKER
+        if (!kwFsPathExists(pszFilename))
+#elif defined(KMK)
         if (!file_exists_p(pszFilename))
 #elif K_OS == K_OS_WINDOWS
         if (birdStatModTimeOnly(pszFilename, &s.st_mtim, 1 /*fFollowLink*/) != 0)
diff --git a/src/lib/kDep.h b/src/lib/kDep.h
index b1c35aa..ad84a53 100644
--- a/src/lib/kDep.h
+++ b/src/lib/kDep.h
@@ -1,4 +1,4 @@
-/* $Id: kDep.h 2851 2016-08-31 17:30:52Z bird $ */
+/* $Id: kDep.h 2955 2016-09-21 19:05:53Z bird $ */
 /** @file
  * kDep - Common Dependency Managemnt Code.
  */
@@ -47,7 +47,7 @@ typedef struct DEP
 
 
 extern PDEP depAdd(const char *pszFilename, size_t cchFilename);
-extern void depOptimize(int fFixCase, int fQuiet);
+extern void depOptimize(int fFixCase, int fQuiet, const char *pszIgnoredExt);
 extern void depPrint(FILE *pOutput);
 extern void depPrintStubs(FILE *pOutput);
 extern void depCleanup(void);
diff --git a/src/lib/kStuff/include/k/kHlpAssert.h b/src/lib/kStuff/include/k/kHlpAssert.h
index 70bc526..aac38be 100644
--- a/src/lib/kStuff/include/k/kHlpAssert.h
+++ b/src/lib/kStuff/include/k/kHlpAssert.h
@@ -1,4 +1,4 @@
-/* $Id: kHlpAssert.h 70 2015-08-13 09:03:02Z bird $ */
+/* $Id: kHlpAssert.h 93 2016-09-15 11:53:59Z bird $ */
 /** @file
  * kHlpAssert - Assertion Macros.
  */
@@ -221,12 +221,18 @@ extern "C" {
 #define kHlpAssertRC(rc)                        kHlpAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
 #define kHlpAssertRCReturn(rc, rcRet)           kHlpAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
 #define kHlpAssertRCReturnVoid(rc)              kHlpAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)))
-#define kHlpAssertFailed()                      kHlpAssert(0)
-#define kHlpAssertFailedReturn(rcRet)           kHlpAssertReturn(0, (rcRet))
-#define kHlpAssertFailedReturnVoid()            kHlpAssertReturnVoid(0)
-#define kHlpAssertMsgFailed(msg)                kHlpAssertMsg(0, msg)
-#define kHlpAssertMsgFailedReturn(msg, rcRet)   kHlpAssertMsgReturn(0, msg, (rcRet))
-#define kHlpAssertMsgFailedReturnVoid(msg)      kHlpAssertMsgReturnVoid(0, msg))
+#define kHlpAssertFailed()                              kHlpAssert(0)
+#define kHlpAssertFailedStmt(stmt)                      kHlpAssertStmt(0, stmt)
+#define kHlpAssertFailedReturn(rcRet)                   kHlpAssertReturn(0, (rcRet))
+#define kHlpAssertFailedStmtReturn(stmt, rcRet)         kHlpAssertStmtReturn(0, stmt, (rcRet))
+#define kHlpAssertFailedReturnVoid()                    kHlpAssertReturnVoid(0)
+#define kHlpAssertFailedStmtReturnVoid(stmt)            kHlpAssertStmtReturnVoid(0, stmt)
+#define kHlpAssertMsgFailed(msg)                        kHlpAssertMsg(0, msg)
+#define kHlpAssertMsgFailedStmt(msg, stmt)              kHlpAssertMsgStmt(0, msg, stmt)
+#define kHlpAssertMsgFailedReturn(msg, rcRet)           kHlpAssertMsgReturn(0, msg, (rcRet))
+#define kHlpAssertMsgFailedStmtReturn(msg, stmt, rcRet) kHlpAssertMsgStmtReturn(0, msg, stmt, (rcRet))
+#define kHlpAssertMsgFailedReturnVoid(msg)              kHlpAssertMsgReturnVoid(0, msg)
+#define kHlpAssertMsgFailedStmtReturnVoid(msg, stmt)    kHlpAssertMsgStmtReturnVoid(0, msg, stmt)
 
 /**
  * Helper function that displays the first part of the assertion message.
diff --git a/src/lib/kStuff/include/k/kTypes.h b/src/lib/kStuff/include/k/kTypes.h
index d79f295..c957566 100644
--- a/src/lib/kStuff/include/k/kTypes.h
+++ b/src/lib/kStuff/include/k/kTypes.h
@@ -1,4 +1,4 @@
-/* $Id: kTypes.h 29 2009-07-01 20:30:29Z bird $ */
+/* $Id: kTypes.h 95 2016-09-26 07:23:08Z bird $ */
 /** @file
  * kTypes - Typedefs And Related Constants And Macros.
  */
@@ -122,9 +122,21 @@
 /** @def KSSIZE_MIN
  * Memory size min constant.*/
 /** @def KSIZE_PRI
- * Memory size printf format. */
+ * Memory size default printf format (hex). */
+/** @def KSIZE_PRI_U
+ * Memory size unsigned decimal printf format. */
+/** @def KSIZE_PRI_I
+ * Memory size signed decimal printf format. */
+/** @def KSIZE_PRI_X
+ * Memory size hexadecimal printf format. */
 /** @def KSSIZE_PRI
- * Memory size printf format. */
+ * Memory size default printf format (hex). */
+/** @def KSSIZE_PRI_U
+ * Memory size unsigned decimal printf format. */
+/** @def KSSIZE_PRI_I
+ * Memory size signed decimal printf format. */
+/** @def KSSIZE_PRI_X
+ * Memory size hexadecimal printf format. */
 
 /** @typedef KIPTR
  * Signed integer type capable of containing a pointer value.  */
@@ -172,7 +184,7 @@ typedef unsigned char           KU8;
 #define KI64_C(c)               (c ## LL)
 #define KU64_C(c)               (c ## ULL)
 #define KI32_C(c)               (c)
-#define KU32_C(c)               (c)
+#define KU32_C(c)               (c ## U)
 #define KI16_C(c)               (c)
 #define KU16_C(c)               (c)
 #define KI8_C(c)                (c)
@@ -198,6 +210,9 @@ typedef KU32                    KSIZE;
 #define KSIZE_C(c)              KU32_C(c)
 #define KSIZE_MAX               KU32_MAX
 #define KSIZE_PRI               KX32_PRI
+#define KSIZE_PRI_U             KU32_PRI
+#define KSIZE_PRI_I             KI32_PRI
+#define KSIZE_PRI_X             KX32_PRI
 #define KIPTR_C(c)              KI32_C(c)
 
 typedef KI32                    KIPTR;
@@ -245,7 +260,7 @@ typedef unsigned short          KU16;
 typedef signed char             KI8;
 typedef unsigned char           KU8;
 #define KI32_C(c)               (c)
-#define KU32_C(c)               (c)
+#define KU32_C(c)               (c ## U)
 #define KI16_C(c)               (c)
 #define KU16_C(c)               (c)
 #define KI8_C(c)                (c)
@@ -266,10 +281,16 @@ typedef KI64                    KSSIZE;
 #define KSSIZE_MAX              KI64_MAX
 #define KSSIZE_MIN              KI64_MIN
 #define KSSIZE_PRI              KX64_PRI
+#define KSSIZE_PRI_U            KU64_PRI
+#define KSSIZE_PRI_I            KI64_PRI
+#define KSSIZE_PRI_X            KX64_PRI
 
 typedef KU64                    KSIZE;
 #define KSIZE_C(c)              KU64_C(c)
 #define KSIZE_MAX               KU64_MAX
+#define KSIZE_PRI_U             KU64_PRI
+#define KSIZE_PRI_I             KI64_PRI
+#define KSIZE_PRI_X             KX64_PRI
 #define KSIZE_PRI               KX64_PRI
 
 typedef KI64                    KIPTR;
diff --git a/src/lib/msc_buffered_printf.c b/src/lib/msc_buffered_printf.c
index 2638b4f..6b7c886 100644
--- a/src/lib/msc_buffered_printf.c
+++ b/src/lib/msc_buffered_printf.c
@@ -1,4 +1,4 @@
-/* $Id: msc_buffered_printf.c 2910 2016-09-10 00:57:29Z bird $ */
+/* $Id: msc_buffered_printf.c 2967 2016-09-26 18:14:13Z bird $ */
 /** @file
  * printf, vprintf, fprintf, puts, fputs console optimizations for Windows/MSC.
  */
@@ -46,6 +46,12 @@
 #undef fputs
 #pragma warning(disable: 4273) /* inconsistent dll linkage*/
 
+#ifndef KWORKER
+# define DLL_IMPORT __declspec(dllexport)
+#else
+# define DLL_IMPORT
+#endif
+
 extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile);
 
 
@@ -56,7 +62,7 @@ extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits,
  * @param   pszFormat           The format string.
  * @param   ...                 Format arguments.
  */
-__declspec(dllexport)
+DLL_IMPORT
 int __cdecl printf(const char *pszFormat, ...)
 {
     int cchRet;
@@ -75,7 +81,7 @@ int __cdecl printf(const char *pszFormat, ...)
  * @param   pszFormat           The format string.
  * @param   va                  Format arguments.
  */
-__declspec(dllexport)
+DLL_IMPORT
 int __cdecl vprintf(const char *pszFormat, va_list va)
 {
     /*
@@ -113,7 +119,7 @@ int __cdecl vprintf(const char *pszFormat, va_list va)
  * @param   pszFormat           The format string.
  * @param   va                  Format arguments.
  */
-__declspec(dllexport)
+DLL_IMPORT
 int __cdecl fprintf(FILE *pFile, const char *pszFormat, ...)
 {
     va_list va;
@@ -159,7 +165,7 @@ int __cdecl fprintf(FILE *pFile, const char *pszFormat, ...)
  * @returns Units written; 0 & errno on failure.
  * @param   pszString           The string to write. (newline is appended)
  */
-__declspec(dllexport)
+DLL_IMPORT
 int __cdecl puts(const char *pszString)
 {
     size_t cchString = strlen(pszString);
@@ -234,7 +240,7 @@ int __cdecl puts(const char *pszString)
  * @param   pszString           The string to write (no newline added).
  * @param   pFile               The output file.
  */
-__declspec(dllexport)
+DLL_IMPORT
 int __cdecl fputs(const char *pszString, FILE *pFile)
 {
     size_t cchString = strlen(pszString);
diff --git a/src/lib/nt/fts-nt.c b/src/lib/nt/fts-nt.c
new file mode 100644
index 0000000..1b815a1
--- /dev/null
+++ b/src/lib/nt/fts-nt.c
@@ -0,0 +1,1015 @@
+/* $Id: fts-nt.c 2992 2016-11-01 22:06:08Z bird $ */
+/** @file
+ * Source for the NT port of BSD fts.c.
+ *
+ * @copyright   1990, 1993, 1994 The Regents of the University of California.  All rights reserved.
+ * @copyright   NT modifications Copyright (C) 2016 knut st. osmundsen <bird-klibc-spam-xiv at anduin.net>
+ * @licenses    BSD3
+ *
+ *
+ * Some hints about how the code works.
+ *
+ * The input directories & files are entered into a pseudo root directory and
+ * processed one after another, depth first.
+ *
+ * Directories are completely read into memory first and arranged as linked
+ * list anchored on FTS::fts_cur.  fts_read does a pop-like operation on that
+ * list, freeing the nodes after they've been completely processed.
+ * Subdirectories are returned twice by fts_read, the first time when it
+ * decends into it (FTS_D), and the second time as it ascends from it (FTS_DP).
+ *
+ * In parallel to fts_read, there's the fts_children API that fetches the
+ * directory content in a similar manner, but for the consumption of the API
+ * caller rather than FTS itself.  The result hangs on FTS::fts_child so it can
+ * be freed when the directory changes or used by fts_read when it is called
+ * upon to enumerate the directory.
+ *
+ *
+ * The NT port of the code does away with the directory changing in favor of
+ * using directory relative opens (present in NT since for ever, just not
+ * exposed thru Win32).  A new FTSENT member fts_dirfd has been added to make
+ * this possible for API users too.
+ *
+ * Note! When using Win32 APIs with path input relative to the current
+ *  	 directory, the internal DOS <-> NT path converter will expand it to a
+ *  	 full path and subject it to the 260 char limit.
+ *
+ * The richer NT directory enumeration API allows us to do away with all the
+ * stat() calls, and not have to do link counting and other interesting things
+ * to try speed things up.  (You typical stat() implementation on windows is
+ * actually a directory enum call with the name of the file as filter.)
+ */
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fts.c	8.6 (Berkeley) 8/14/94";
+#endif /* LIBC_SCCS and not lint */
+#endif
+
+#include <errno.h>
+#include "fts-nt.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "nthlp.h"
+#include "ntdir.h"
+
+static FTSENT	*fts_alloc(FTS *, char *, size_t);
+static FTSENT	*fts_build(FTS *, int);
+static void	 fts_lfree(FTSENT *);
+static void	 fts_load(FTS *, FTSENT *);
+static size_t	 fts_maxarglen(char * const *);
+static void	 fts_padjust(FTS *, FTSENT *);
+static int	 fts_palloc(FTS *, size_t);
+static FTSENT	*fts_sort(FTS *, FTSENT *, size_t);
+static int	 fts_stat(FTS *, FTSENT *, int, HANDLE);
+static int	 fts_process_stats(FTSENT *, BirdStat_T const *);
+
+#define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+
+#define	CLR(opt)	(sp->fts_options &= ~(opt))
+#define	ISSET(opt)	(sp->fts_options & (opt))
+#define	SET(opt)	(sp->fts_options |= (opt))
+
+/* fts_build flags */
+#define	BCHILD		1		/* fts_children */
+#define	BNAMES		2		/* fts_children, names only */
+#define	BREAD		3		/* fts_read */
+
+/* NT needs these: */
+#define MAXPATHLEN 260
+#define MAX(a, b)  ( (a) >= (b) ? (a) : (b) )
+
+#define AT_SYMLINK_NOFOLLOW 1
+#define fstatat(hDir, pszPath, pStat, fFlags) birdStatAt((hDir), (pszPath), (pStat), (fFlags) != AT_SYMLINK_NOFOLLOW)
+#define FTS_NT_DUMMY_SYMFD_VALUE 	((HANDLE)~(intptr_t)(2)) /* current process */
+
+/*
+ * Internal representation of an FTS, including extra implementation
+ * details.  The FTS returned from fts_open points to this structure's
+ * ftsp_fts member (and can be cast to an _fts_private as required)
+ */
+struct _fts_private {
+	FTS		ftsp_fts;
+};
+
+
+FTS * FTSCALL
+nt_fts_open(char * const *argv, int options,
+    int (*compar)(const FTSENT * const *, const FTSENT * const *))
+{
+	struct _fts_private *priv;
+	FTS *sp;
+	FTSENT *p, *root;
+	FTSENT *parent, *tmp;
+	size_t len, nitems;
+
+	/* Options check. */
+	if (options & ~FTS_OPTIONMASK) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* fts_open() requires at least one path */
+	if (*argv == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* Allocate/initialize the stream. */
+	if ((priv = calloc(1, sizeof(*priv))) == NULL)
+		return (NULL);
+	sp = &priv->ftsp_fts;
+	sp->fts_compar = compar;
+	sp->fts_options = options;
+	SET(FTS_NOCHDIR); /* NT: FTS_NOCHDIR is always on (for external consumes) */
+
+	/* Shush, GCC. */
+	tmp = NULL;
+
+	/*
+	 * Start out with 1K of path space, and enough, in any case,
+	 * to hold the user's paths.
+	 */
+	if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+		goto mem1;
+
+	/* Allocate/initialize root's parent. */
+	if ((parent = fts_alloc(sp, "", 0)) == NULL)
+		goto mem2;
+	parent->fts_level = FTS_ROOTPARENTLEVEL;
+
+	/* Allocate/initialize root(s). */
+	for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
+		/* NT: We need to do some small input transformations to make this and
+		       the API user code happy.  1. Lone drive letters get a dot
+		       appended so it won't matter if a slash is appended afterwards.
+		       2. DOS slashes are converted to UNIX ones. */
+		char *slash;
+		len = strlen(*argv);
+		if (len == 2 && argv[0][1] == ':') {
+			char tmp[4];
+			tmp[0] = argv[0][0];
+			tmp[1] = ':';
+			tmp[2] = '.';
+			tmp[3] = '\0';
+			p = fts_alloc(sp, tmp, 3);
+		} else {
+			p = fts_alloc(sp, *argv, len);
+		}
+#if 1 /* bird */
+		if (p != NULL) { /* likely */ } else { goto mem3; }
+#endif
+		slash = strchr(p->fts_name, '\\');
+		while (slash != NULL) {
+			*slash++ = '/';
+			slash = strchr(p->fts_name, '\\');
+		}
+		p->fts_level = FTS_ROOTLEVEL;
+		p->fts_parent = parent;
+		p->fts_accpath = p->fts_name;
+		p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), INVALID_HANDLE_VALUE);
+
+		/* Command-line "." and ".." are real directories. */
+		if (p->fts_info == FTS_DOT)
+			p->fts_info = FTS_D;
+
+		/*
+		 * If comparison routine supplied, traverse in sorted
+		 * order; otherwise traverse in the order specified.
+		 */
+		if (compar) {
+			p->fts_link = root;
+			root = p;
+		} else {
+			p->fts_link = NULL;
+			if (root == NULL)
+				tmp = root = p;
+			else {
+				tmp->fts_link = p;
+				tmp = p;
+			}
+		}
+	}
+	if (compar && nitems > 1)
+		root = fts_sort(sp, root, nitems);
+
+	/*
+	 * Allocate a dummy pointer and make fts_read think that we've just
+	 * finished the node before the root(s); set p->fts_info to FTS_INIT
+	 * so that everything about the "current" node is ignored.
+	 */
+	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+		goto mem3;
+	sp->fts_cur->fts_link = root;
+	sp->fts_cur->fts_info = FTS_INIT;
+
+	return (sp);
+
+mem3:	fts_lfree(root);
+	free(parent);
+mem2:	free(sp->fts_path);
+mem1:	free(sp);
+	return (NULL);
+}
+
+
+static void
+fts_load(FTS *sp, FTSENT *p)
+{
+	size_t len;
+	char *cp;
+
+	/*
+	 * Load the stream structure for the next traversal.  Since we don't
+	 * actually enter the directory until after the preorder visit, set
+	 * the fts_accpath field specially so the chdir gets done to the right
+	 * place and the user can access the first node.  From fts_open it's
+	 * known that the path will fit.
+	 */
+	len = p->fts_pathlen = p->fts_namelen;
+	memmove(sp->fts_path, p->fts_name, len + 1);
+	if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+		len = strlen(++cp);
+		memmove(p->fts_name, cp, len + 1);
+		p->fts_namelen = len;
+	}
+	p->fts_accpath = p->fts_path = sp->fts_path;
+	sp->fts_dev = p->fts_dev;
+}
+
+int FTSCALL
+nt_fts_close(FTS *sp)
+{
+	FTSENT *freep, *p;
+	/*int saved_errno;*/
+
+	/*
+	 * This still works if we haven't read anything -- the dummy structure
+	 * points to the root list, so we step through to the end of the root
+	 * list which has a valid parent pointer.
+	 */
+	if (sp->fts_cur) {
+		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+			freep = p;
+			p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
+			free(freep);
+		}
+		free(p);
+	}
+
+	/* Free up child linked list, sort array, path buffer. */
+	if (sp->fts_child)
+		fts_lfree(sp->fts_child);
+	if (sp->fts_array)
+		free(sp->fts_array);
+	free(sp->fts_path);
+
+	/* Free up the stream pointer. */
+	free(sp);
+	return (0);
+}
+
+/*
+ * Special case of "/" at the end of the path so that slashes aren't
+ * appended which would cause paths to be written as "....//foo".
+ */
+#define	NAPPEND(p)							\
+	(p->fts_path[p->fts_pathlen - 1] == '/'				\
+	    ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+static void
+fts_free_entry(FTSENT *tmp)
+{
+    if (tmp != NULL) {
+		if (tmp->fts_dirfd != INVALID_HANDLE_VALUE) {
+			birdCloseFile(tmp->fts_dirfd);
+			tmp->fts_dirfd = INVALID_HANDLE_VALUE;
+		}
+		free(tmp);
+    }
+}
+
+FTSENT * FTSCALL
+nt_fts_read(FTS *sp)
+{
+	FTSENT *p, *tmp;
+	int instr;
+	char *t;
+
+	/* If finished or unrecoverable error, return NULL. */
+	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+		return (NULL);
+
+	/* Set current node pointer. */
+	p = sp->fts_cur;
+
+	/* Save and zero out user instructions. */
+	instr = p->fts_instr;
+	p->fts_instr = FTS_NOINSTR;
+
+	/* Any type of file may be re-visited; re-stat and re-turn. */
+	if (instr == FTS_AGAIN) {
+		p->fts_info = fts_stat(sp, p, 0, INVALID_HANDLE_VALUE);
+		return (p);
+	}
+
+	/*
+	 * Following a symlink -- SLNONE test allows application to see
+	 * SLNONE and recover.  If indirecting through a symlink, have
+	 * keep a pointer to current location.  If unable to get that
+	 * pointer, follow fails.
+	 *
+	 * NT: Since we don't change directory, we just set fts_symfd to a
+	 *     placeholder value handle value here in case a API client
+	 *     checks it. Ditto FTS_SYMFOLLOW.
+	 */
+	if (instr == FTS_FOLLOW &&
+	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+		p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE);
+		if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) {
+			p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;
+			p->fts_flags |= FTS_SYMFOLLOW;
+		}
+		return (p);
+	}
+
+	/* Directory in pre-order. */
+	if (p->fts_info == FTS_D) {
+		/* If skipped or crossed mount point, do post-order visit. */
+		if (instr == FTS_SKIP ||
+		    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
+			if (p->fts_flags & FTS_SYMFOLLOW) {
+				p->fts_symfd = INVALID_HANDLE_VALUE;
+			}
+			if (sp->fts_child) {
+				fts_lfree(sp->fts_child);
+				sp->fts_child = NULL;
+			}
+			p->fts_info = FTS_DP;
+			return (p);
+		}
+
+		/* Rebuild if only read the names and now traversing. */
+		if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
+			CLR(FTS_NAMEONLY);
+			fts_lfree(sp->fts_child);
+			sp->fts_child = NULL;
+		}
+
+		/*
+		 * Cd to the subdirectory.
+		 *
+		 * If have already read and now fail to chdir, whack the list
+		 * to make the names come out right, and set the parent errno
+		 * so the application will eventually get an error condition.
+		 * Set the FTS_DONTCHDIR flag so that when we logically change
+		 * directories back to the parent we don't do a chdir.
+		 *
+		 * If haven't read do so.  If the read fails, fts_build sets
+		 * FTS_STOP or the fts_info field of the node.
+		 */
+		if (sp->fts_child != NULL) {
+			/* nothing to do */
+		} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+			if (ISSET(FTS_STOP))
+				return (NULL);
+			return (p);
+		}
+		p = sp->fts_child;
+		sp->fts_child = NULL;
+		goto name;
+	}
+
+	/* Move to the next node on this level. */
+next:	tmp = p;
+	if ((p = p->fts_link) != NULL) {
+		/*
+		 * If reached the top, return to the original directory (or
+		 * the root of the tree), and load the paths for the next root.
+		 */
+		if (p->fts_level == FTS_ROOTLEVEL) {
+			fts_free_entry(tmp);
+			fts_load(sp, p);
+			return (sp->fts_cur = p);
+		}
+
+		/*
+		 * User may have called fts_set on the node.  If skipped,
+		 * ignore.  If followed, get a file descriptor so we can
+		 * get back if necessary.
+		 */
+		if (p->fts_instr == FTS_SKIP) {
+			fts_free_entry(tmp);
+			goto next;
+		}
+		if (p->fts_instr == FTS_FOLLOW) {
+			p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE);
+			/* NT: See above regarding fts_symfd. */
+			if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) {
+				p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;
+				p->fts_flags |= FTS_SYMFOLLOW;
+			}
+			p->fts_instr = FTS_NOINSTR;
+		}
+
+		fts_free_entry(tmp);
+
+name:		t = sp->fts_path + NAPPEND(p->fts_parent);
+		*t++ = '/';
+		memmove(t, p->fts_name, p->fts_namelen + 1);
+		return (sp->fts_cur = p);
+	}
+
+	/* Move up to the parent node. */
+	p = tmp->fts_parent;
+
+	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+		/*
+		 * Done; free everything up and set errno to 0 so the user
+		 * can distinguish between error and EOF.
+		 */
+		fts_free_entry(tmp);
+		fts_free_entry(p);
+		errno = 0;
+		return (sp->fts_cur = NULL);
+	}
+
+	/* NUL terminate the pathname. */
+	sp->fts_path[p->fts_pathlen] = '\0';
+
+	/*
+	 * Return to the parent directory.  If at a root node or came through
+	 * a symlink, go back through the file descriptor.  Otherwise, cd up
+	 * one directory.
+	 *
+	 * NT: We're doing no fchdir, but we need to close the directory handle
+	 *     and clear fts_symfd now.
+	 */
+	if (p->fts_flags & FTS_SYMFOLLOW) {
+		p->fts_symfd = INVALID_HANDLE_VALUE;
+	}
+    if (p->fts_dirfd != INVALID_HANDLE_VALUE) {
+		birdCloseFile(p->fts_dirfd);
+		p->fts_dirfd = INVALID_HANDLE_VALUE;
+    }
+    fts_free_entry(tmp);
+	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+	return (sp->fts_cur = p);
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set.  An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int FTSCALL
+nt_fts_set(FTS *sp, FTSENT *p, int instr)
+{
+	if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+	    instr != FTS_NOINSTR && instr != FTS_SKIP) {
+		errno = EINVAL;
+		return (1);
+	}
+	p->fts_instr = instr;
+	return (0);
+}
+
+FTSENT * FTSCALL
+nt_fts_children(FTS *sp, int instr)
+{
+	FTSENT *p;
+
+	if (instr != 0 && instr != FTS_NAMEONLY) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* Set current node pointer. */
+	p = sp->fts_cur;
+
+	/*
+	 * Errno set to 0 so user can distinguish empty directory from
+	 * an error.
+	 */
+	errno = 0;
+
+	/* Fatal errors stop here. */
+	if (ISSET(FTS_STOP))
+		return (NULL);
+
+	/* Return logical hierarchy of user's arguments. */
+	if (p->fts_info == FTS_INIT)
+		return (p->fts_link);
+
+	/*
+	 * If not a directory being visited in pre-order, stop here.  Could
+	 * allow FTS_DNR, assuming the user has fixed the problem, but the
+	 * same effect is available with FTS_AGAIN.
+	 */
+	if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+		return (NULL);
+
+	/* Free up any previous child list. */
+	if (sp->fts_child != NULL) {
+		fts_lfree(sp->fts_child);
+		sp->fts_child = NULL; /* (bird - double free for _open(".") failure in original) */
+	}
+
+	/* NT: Some BSD utility sets FTS_NAMEONLY? We don't really need this
+	       optimization, but since it only hurts that utility, it can stay.  */
+	if (instr == FTS_NAMEONLY) {
+		assert(0); /* don't specify FTS_NAMEONLY on NT. */
+		SET(FTS_NAMEONLY);
+		instr = BNAMES;
+	} else
+		instr = BCHILD;
+
+	return (sp->fts_child = fts_build(sp, instr));
+}
+
+#ifndef fts_get_clientptr
+#error "fts_get_clientptr not defined"
+#endif
+
+void *
+(FTSCALL fts_get_clientptr)(FTS *sp)
+{
+
+	return (fts_get_clientptr(sp));
+}
+
+#ifndef fts_get_stream
+#error "fts_get_stream not defined"
+#endif
+
+FTS *
+(FTSCALL fts_get_stream)(FTSENT *p)
+{
+	return (fts_get_stream(p));
+}
+
+void FTSCALL
+nt_fts_set_clientptr(FTS *sp, void *clientptr)
+{
+
+	sp->fts_clientptr = clientptr;
+}
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here.  The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read.  There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly.  First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry.  Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls.  The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ *
+ * NT: We do not do any link counting or stat avoiding, which invalidates the
+ *     above warnings.  This function is very simple for us.
+ */
+static FTSENT *
+fts_build(FTS *sp, int type)
+{
+	BirdDirEntry_T *dp;
+	FTSENT *p, *head;
+	FTSENT *cur, *tail;
+	DIR *dirp;
+	void *oldaddr;
+	char *cp;
+	int saved_errno, doadjust;
+	long level;
+	size_t dnamlen, len, maxlen, nitems;
+	unsigned fDirOpenFlags;
+
+	/* Set current node pointer. */
+	cur = sp->fts_cur;
+
+	/*
+	 * Open the directory for reading.  If this fails, we're done.
+	 * If being called from fts_read, set the fts_info field.
+	 *
+	 * NT: We do a two stage open so we can keep the directory handle around
+	 *     after we've enumerated the directory.  The dir handle is used by
+	 *     us here and by the API users to more efficiently and safely open
+	 *     members of the directory.
+	 */
+	fDirOpenFlags = BIRDDIR_F_EXTRA_INFO | BIRDDIR_F_KEEP_HANDLE;
+    if (cur->fts_dirfd == INVALID_HANDLE_VALUE) {
+		if (cur->fts_parent->fts_dirfd != INVALID_HANDLE_VALUE) {
+			/* (This works fine for symlinks too, since we follow them.) */
+			cur->fts_dirfd = birdOpenFileEx(cur->fts_parent->fts_dirfd,
+											cur->fts_name,
+											FILE_READ_DATA | SYNCHRONIZE,
+											FILE_ATTRIBUTE_NORMAL,
+											FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+											FILE_OPEN,
+											FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+											OBJ_CASE_INSENSITIVE);
+		} else {
+			cur->fts_dirfd = birdOpenFile(cur->fts_accpath,
+										  FILE_READ_DATA | SYNCHRONIZE,
+										  FILE_ATTRIBUTE_NORMAL,
+										  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+										  FILE_OPEN,
+										  FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+										  OBJ_CASE_INSENSITIVE);
+		}
+    } else {
+		fDirOpenFlags |= BIRDDIR_F_RESTART_SCAN;
+	}
+	dirp = birdDirOpenFromHandle(cur->fts_dirfd, NULL, fDirOpenFlags);
+	if (dirp == NULL) {
+		if (type == BREAD) {
+			cur->fts_info = FTS_DNR;
+			cur->fts_errno = errno;
+		}
+		return (NULL);
+	}
+
+	/*
+	 * Figure out the max file name length that can be stored in the
+	 * current path -- the inner loop allocates more path as necessary.
+	 * We really wouldn't have to do the maxlen calculations here, we
+	 * could do them in fts_read before returning the path, but it's a
+	 * lot easier here since the length is part of the dirent structure.
+	 *
+	 * If not changing directories set a pointer so that can just append
+	 * each new name into the path.
+	 */
+	len = NAPPEND(cur);
+	cp = sp->fts_path + len;
+	*cp++ = '/';
+	len++;
+	maxlen = sp->fts_pathlen - len;
+
+	level = cur->fts_level + 1;
+
+	/* Read the directory, attaching each entry to the `link' pointer. */
+	doadjust = 0;
+	for (head = tail = NULL, nitems = 0; dirp && (dp = birdDirRead(dirp));) {
+		dnamlen = dp->d_namlen;
+		if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+			continue;
+
+		if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL)
+			goto mem1;
+		if (dnamlen >= maxlen) {	/* include space for NUL */
+			oldaddr = sp->fts_path;
+			if (fts_palloc(sp, dnamlen + len + 1)) {
+				/*
+				 * No more memory for path or structures.  Save
+				 * errno, free up the current structure and the
+				 * structures already allocated.
+				 */
+mem1:				saved_errno = errno;
+				if (p)
+					free(p);
+				fts_lfree(head);
+				birdDirClose(dirp);
+				birdCloseFile(cur->fts_dirfd);
+				cur->fts_dirfd = INVALID_HANDLE_VALUE;
+				cur->fts_info = FTS_ERR;
+				SET(FTS_STOP);
+				errno = saved_errno;
+				return (NULL);
+			}
+			/* Did realloc() change the pointer? */
+			if (oldaddr != sp->fts_path) {
+				doadjust = 1;
+				if (1 /*ISSET(FTS_NOCHDIR)*/)
+					cp = sp->fts_path + len;
+			}
+			maxlen = sp->fts_pathlen - len;
+		}
+
+		p->fts_level = level;
+		p->fts_parent = sp->fts_cur;
+		p->fts_pathlen = len + dnamlen;
+		p->fts_accpath = p->fts_path;
+		p->fts_stat = dp->d_stat;
+		p->fts_info = fts_process_stats(p, &dp->d_stat);
+
+		/* We walk in directory order so "ls -f" doesn't get upset. */
+		p->fts_link = NULL;
+		if (head == NULL)
+			head = tail = p;
+		else {
+			tail->fts_link = p;
+			tail = p;
+		}
+		++nitems;
+	}
+
+	birdDirClose(dirp);
+
+	/*
+	 * If realloc() changed the address of the path, adjust the
+	 * addresses for the rest of the tree and the dir list.
+	 */
+	if (doadjust)
+		fts_padjust(sp, head);
+
+	/*
+	 * Reset the path back to original state.
+	 */
+	sp->fts_path[cur->fts_pathlen] = '\0';
+
+	/* If didn't find anything, return NULL. */
+	if (!nitems) {
+		if (type == BREAD)
+			cur->fts_info = FTS_DP;
+		return (NULL);
+	}
+
+	/* Sort the entries. */
+	if (sp->fts_compar && nitems > 1)
+		head = fts_sort(sp, head, nitems);
+	return (head);
+}
+
+
+/**
+ * @note Only used on NT with input arguments, FTS_AGAIN, and links that needs
+ *  	 following.  On link information is generally retrieved during directory
+ *  	 enumeration on NT, in line with it's DOS/OS2/FAT API heritage.
+ */
+static int
+fts_stat(FTS *sp, FTSENT *p, int follow, HANDLE dfd)
+{
+	int saved_errno;
+	const char *path;
+
+	if (dfd == INVALID_HANDLE_VALUE) {
+		path = p->fts_accpath;
+	} else {
+		path = p->fts_name;
+	}
+
+	/*
+	 * If doing a logical walk, or application requested FTS_FOLLOW, do
+	 * a stat(2).  If that fails, check for a non-existent symlink.  If
+	 * fail, set the errno from the stat call.
+	 */
+	if (ISSET(FTS_LOGICAL) || follow) {
+		if (fstatat(dfd, path, &p->fts_stat, 0)) {
+			saved_errno = errno;
+			if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) {
+				p->fts_errno = saved_errno;
+				goto err;
+			}
+			errno = 0;
+			if (S_ISLNK(p->fts_stat.st_mode))
+				return (FTS_SLNONE);
+		}
+	} else if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) {
+		p->fts_errno = errno;
+err:		memset(&p->fts_stat, 0, sizeof(struct stat));
+		return (FTS_NS);
+	}
+	return fts_process_stats(p, &p->fts_stat);
+}
+
+/* Shared between fts_stat and fts_build. */
+static int 
+fts_process_stats(FTSENT *p, BirdStat_T const *sbp)
+{
+	if (S_ISDIR(sbp->st_mode)) {
+		FTSENT *t;
+		fts_dev_t dev;
+		fts_ino_t ino;
+
+		/*
+		 * Set the device/inode.  Used to find cycles and check for
+		 * crossing mount points.  Also remember the link count, used
+		 * in fts_build to limit the number of stat calls.  It is
+		 * understood that these fields are only referenced if fts_info
+		 * is set to FTS_D.
+		 */
+		dev = p->fts_dev = sbp->st_dev;
+		ino = p->fts_ino = sbp->st_ino;
+		p->fts_nlink = sbp->st_nlink;
+
+		if (ISDOT(p->fts_name))
+			return (FTS_DOT);
+
+		/*
+		 * Cycle detection is done by brute force when the directory
+		 * is first encountered.  If the tree gets deep enough or the
+		 * number of symbolic links to directories is high enough,
+		 * something faster might be worthwhile.
+		 */
+		for (t = p->fts_parent;
+		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+			if (ino == t->fts_ino && dev == t->fts_dev) {
+				p->fts_cycle = t;
+				return (FTS_DC);
+			}
+		return (FTS_D);
+	}
+	if (S_ISLNK(sbp->st_mode))
+		return (FTS_SL);
+	if (S_ISREG(sbp->st_mode))
+		return (FTS_F);
+	return (FTS_DEFAULT);
+}
+
+/*
+ * The comparison function takes pointers to pointers to FTSENT structures.
+ * Qsort wants a comparison function that takes pointers to void.
+ * (Both with appropriate levels of const-poisoning, of course!)
+ * Use a trampoline function to deal with the difference.
+ */
+static int
+fts_compar(const void *a, const void *b)
+{
+	FTS *parent;
+
+	parent = (*(const FTSENT * const *)a)->fts_fts;
+	return (*parent->fts_compar)(a, b);
+}
+
+static FTSENT *
+fts_sort(FTS *sp, FTSENT *head, size_t nitems)
+{
+	FTSENT **ap, *p;
+
+	/*
+	 * Construct an array of pointers to the structures and call qsort(3).
+	 * Reassemble the array in the order returned by qsort.  If unable to
+	 * sort for memory reasons, return the directory entries in their
+	 * current order.  Allocate enough space for the current needs plus
+	 * 40 so don't realloc one entry at a time.
+	 */
+	if (nitems > sp->fts_nitems) {
+		void *ptr;
+		sp->fts_nitems = nitems + 40;
+		ptr = realloc(sp->fts_array, sp->fts_nitems * sizeof(FTSENT *));
+		if (ptr != NULL) {
+			sp->fts_array = ptr;
+		} else {
+			free(sp->fts_array);
+			sp->fts_array = NULL;
+			sp->fts_nitems = 0;
+			return (head);
+		}
+	}
+	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
+		*ap++ = p;
+	qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
+	for (head = *(ap = sp->fts_array); --nitems; ++ap)
+		ap[0]->fts_link = ap[1];
+	ap[0]->fts_link = NULL;
+	return (head);
+}
+
+static FTSENT *
+fts_alloc(FTS *sp, char *name, size_t namelen)
+{
+	FTSENT *p;
+	size_t len;
+
+	struct ftsent_withstat {
+		FTSENT	ent;
+		struct	stat statbuf;
+	};
+
+	/*
+	 * The file name is a variable length array.  Allocate the FTSENT
+	 * structure and the file name.
+	 */
+	len = sizeof(FTSENT) + namelen + 1;
+	if ((p = malloc(len)) == NULL)
+		return (NULL);
+
+	p->fts_name = (char *)(p + 1);
+	p->fts_statp = &p->fts_stat;
+
+	/* Copy the name and guarantee NUL termination. */
+	memcpy(p->fts_name, name, namelen);
+	p->fts_name[namelen] = '\0';
+	p->fts_namelen = namelen;
+	p->fts_path = sp->fts_path;
+	p->fts_errno = 0;
+	p->fts_flags = 0;
+	p->fts_instr = FTS_NOINSTR;
+	p->fts_number = 0;
+	p->fts_pointer = NULL;
+	p->fts_fts = sp;
+	p->fts_symfd = INVALID_HANDLE_VALUE;
+	p->fts_dirfd = INVALID_HANDLE_VALUE;
+	return (p);
+}
+
+static void
+fts_lfree(FTSENT *head)
+{
+	FTSENT *p;
+
+	/* Free a linked list of structures. */
+	while ((p = head)) {
+		head = head->fts_link;
+		assert(p->fts_dirfd == INVALID_HANDLE_VALUE);
+		free(p);
+	}
+}
+
+/*
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * though the kernel won't resolve them.  Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
+ */
+static int
+fts_palloc(FTS *sp, size_t more)
+{
+	void *ptr;
+
+	sp->fts_pathlen += more + 256;
+	ptr = realloc(sp->fts_path, sp->fts_pathlen);
+	if (ptr) {
+		/*likely */
+	} else {
+		free(sp->fts_path);
+	}
+	sp->fts_path = ptr;
+	return (ptr == NULL);
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+fts_padjust(FTS *sp, FTSENT *head)
+{
+	FTSENT *p;
+	char *addr = sp->fts_path;
+
+#define	ADJUST(p) do {							\
+	if ((p)->fts_accpath != (p)->fts_name) {			\
+		(p)->fts_accpath =					\
+		    (char *)addr + ((p)->fts_accpath - (p)->fts_path);	\
+	}								\
+	(p)->fts_path = addr;						\
+} while (0)
+	/* Adjust the current set of children. */
+	for (p = sp->fts_child; p; p = p->fts_link)
+		ADJUST(p);
+
+	/* Adjust the rest of the tree, including the current level. */
+	for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
+		ADJUST(p);
+		p = p->fts_link ? p->fts_link : p->fts_parent;
+	}
+}
+
+static size_t
+fts_maxarglen(char * const *argv)
+{
+	size_t len, max;
+
+	for (max = 0; *argv; ++argv)
+		if ((len = strlen(*argv)) > max)
+			max = len;
+	return (max + 1);
+}
+
diff --git a/src/lib/nt/fts-nt.h b/src/lib/nt/fts-nt.h
new file mode 100644
index 0000000..dc990b0
--- /dev/null
+++ b/src/lib/nt/fts-nt.h
@@ -0,0 +1,177 @@
+/* $Id: fts-nt.h 2997 2016-11-01 23:28:02Z bird $ */
+/** @file
+ * Header for the NT port of BSD fts.h.
+ *
+ * @copyright   Copyright (c) 1989, 1993 The Regents of the University of California.  All rights reserved.
+ * @copyright   NT modifications Copyright (C) 2016 knut st. osmundsen <bird-klibc-spam-xiv at anduin.net>
+ * @licenses    BSD3
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)fts.h	8.3 (Berkeley) 8/14/94
+ * $FreeBSD$
+ *
+ */
+
+#ifndef	INCLUDED_FTS_NT_H
+#define	INCLUDED_FTS_NT_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include "ntstat.h" /* ensure correct stat structure */
+
+typedef uint64_t fts_dev_t;
+typedef uint64_t fts_ino_t;
+typedef uint32_t fts_nlink_t;
+#ifdef _WINNT_
+typedef HANDLE fts_fd_t;
+# define NT_FTS_INVALID_HANDLE_VALUE	INVALID_HANDLE_VALUE
+#else
+typedef void * fts_fd_t;
+# define NT_FTS_INVALID_HANDLE_VALUE	((void *)~(uintptr_t)0)
+#endif
+#define FTSCALL __cdecl
+
+typedef struct {
+	struct _ftsent *fts_cur;	/* current node */
+	struct _ftsent *fts_child;	/* linked list of children */
+	struct _ftsent **fts_array;	/* sort array */
+	fts_dev_t fts_dev;		/* starting device # */
+	char *fts_path;			/* path for this descent */
+	size_t fts_pathlen;		/* sizeof(path) */
+	size_t fts_nitems;		/* elements in the sort array */
+	int (FTSCALL *fts_compar)	/* compare function */
+	    (const struct _ftsent * const *, const struct _ftsent * const *);
+
+#define	FTS_COMFOLLOW	0x001		/* follow command line symlinks */
+#define	FTS_LOGICAL	0x002		/* logical walk */
+#define	FTS_NOCHDIR	0x004		/* don't change directories */
+#define	FTS_NOSTAT	0x008		/* don't get stat info */
+#define	FTS_PHYSICAL	0x010		/* physical walk */
+#define	FTS_SEEDOT	0x020		/* return dot and dot-dot */
+#define	FTS_XDEV	0x040		/* don't cross devices */
+#if 0 /* No whiteout on NT. */
+#define	FTS_WHITEOUT	0x080		/* return whiteout information */
+#endif
+#define	FTS_OPTIONMASK	0x0ff		/* valid user option mask */
+
+#define	FTS_NAMEONLY	0x100		/* (private) child names only */
+#define	FTS_STOP	0x200		/* (private) unrecoverable error */
+	int fts_options;		/* fts_open options, global flags */
+	void *fts_clientptr;		/* thunk for sort function */
+} FTS;
+
+typedef struct _ftsent {
+	struct _ftsent *fts_cycle;	/* cycle node */
+	struct _ftsent *fts_parent;	/* parent directory */
+	struct _ftsent *fts_link;	/* next file in directory */
+	int64_t fts_number;		/* local numeric value */
+#define	fts_bignum	fts_number	/* XXX non-std, should go away */
+	void *fts_pointer;		/* local address value */
+	char *fts_accpath;		/* access path */
+	char *fts_path;			/* root path */
+	int fts_errno;			/* errno for this node */
+	fts_fd_t fts_symfd;		/* NT: Normally -1; -2 we followed this symlinked dir */
+	fts_fd_t fts_dirfd;		/* NT: Handle to the directory (NT_FTS_)INVALID_HANDLE_VALUE if not valid */
+	size_t fts_pathlen;		/* strlen(fts_path) */
+	size_t fts_namelen;		/* strlen(fts_name) */
+
+	fts_ino_t fts_ino;		/* inode */
+	fts_dev_t fts_dev;		/* device */
+	fts_nlink_t fts_nlink;		/* link count */
+
+#define	FTS_ROOTPARENTLEVEL	-1
+#define	FTS_ROOTLEVEL		 0
+	long fts_level;			/* depth (-1 to N) */
+
+#define	FTS_D		 1		/* preorder directory */
+#define	FTS_DC		 2		/* directory that causes cycles */
+#define	FTS_DEFAULT	 3		/* none of the above */
+#define	FTS_DNR		 4		/* unreadable directory */
+#define	FTS_DOT		 5		/* dot or dot-dot */
+#define	FTS_DP		 6		/* postorder directory */
+#define	FTS_ERR		 7		/* error; errno is set */
+#define	FTS_F		 8		/* regular file */
+#define	FTS_INIT	 9		/* initialized only */
+#define	FTS_NS		10		/* stat(2) failed */
+#define	FTS_NSOK	11		/* no stat(2) requested */
+#define	FTS_SL		12		/* symbolic link */
+#define	FTS_SLNONE	13		/* symbolic link without target */
+//#define	FTS_W		14		/* whiteout object */
+	int fts_info;			/* user status for FTSENT structure */
+
+#define	FTS_DONTCHDIR	 0x01		/* don't chdir .. to the parent */
+#define	FTS_SYMFOLLOW	 0x02		/* followed a symlink to get here */
+#define	FTS_ISW		 0x04		/* this is a whiteout object */
+	unsigned fts_flags;		/* private flags for FTSENT structure */
+
+#define	FTS_AGAIN	 1		/* read node again */
+#define	FTS_FOLLOW	 2		/* follow symbolic link */
+#define	FTS_NOINSTR	 3		/* no instructions */
+#define	FTS_SKIP	 4		/* discard node */
+	int fts_instr;			/* fts_set() instructions */
+
+	struct stat *fts_statp;		/* stat(2) information */
+	char *fts_name;			/* file name */
+	FTS *fts_fts;			/* back pointer to main FTS */
+	BirdStat_T fts_stat;		/* NT: We always got stat info. */
+} FTSENT;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+FTSENT	*FTSCALL nt_fts_children(FTS *, int);
+int	 FTSCALL nt_fts_close(FTS *);
+void	*FTSCALL nt_fts_get_clientptr(FTS *);
+#define	 fts_get_clientptr(fts)	((fts)->fts_clientptr)
+FTS	*FTSCALL nt_fts_get_stream(FTSENT *);
+#define	 fts_get_stream(ftsent)	((ftsent)->fts_fts)
+FTS	*FTSCALL nt_fts_open(char * const *, int,
+	    int (FTSCALL*)(const FTSENT * const *, const FTSENT * const *));
+FTSENT	*FTSCALL nt_fts_read(FTS *);
+int	 FTSCALL nt_fts_set(FTS *, FTSENT *, int);
+void	 FTSCALL nt_fts_set_clientptr(FTS *, void *);
+
+/* API mappings. */
+#define fts_children(a_pFts, a_iInstr)                  nt_fts_children(a_pFts, a_iInstr)
+#define fts_close(a_pFts)                               nt_fts_close(a_pFts)
+#define fts_open(a_papszArgs, a_fOptions, a_pfnCompare) nt_fts_open(a_papszArgs, a_fOptions, a_pfnCompare)
+#define fts_read(a_pFts)                                nt_fts_read(a_pFts)
+#define fts_set(a_pFts, a_pFtsEntry, a_iInstr)          nt_fts_set(a_pFts, a_pFtsEntry, a_iInstr)
+#define fts_set_clientptr(a_pFts, a_pvUser)             nt_fts_set_clientptr(a_pFts, a_pvUser)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !INCLUDED_FTS_NT_H */
+
diff --git a/src/lib/nt/kFsCache.c b/src/lib/nt/kFsCache.c
index dd3140b..cb28198 100644
--- a/src/lib/nt/kFsCache.c
+++ b/src/lib/nt/kFsCache.c
@@ -1,4 +1,4 @@
-/* $Id: kFsCache.c 2879 2016-09-05 20:14:21Z bird $ */
+/* $Id: kFsCache.c 2985 2016-11-01 18:26:35Z bird $ */
 /** @file
  * ntdircache.c - NT directory content cache.
  */
@@ -40,7 +40,9 @@
 #include <stdio.h>
 #include <mbstring.h>
 #include <wchar.h>
-//#include <intrin.h>
+#ifdef _MSC_VER
+# include <intrin.h>
+#endif
 //#include <setjmp.h>
 //#include <ctype.h>
 
@@ -87,6 +89,11 @@ typedef KFSDIRREPOP *PKFSDIRREPOP;
 
 
 
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError);
+
 
 /**
  * Retains a reference to a cache object, internal version.
@@ -199,12 +206,12 @@ static KSIZE kFsCacheStrHashEx(const char *pszString, KU32 *puHash)
  * @param   pchString           Pointer to the substring (not terminated).
  * @param   cchString           The length of the substring.
  */
-static KU32 kFsCacheStrHashN(const char *pszString, KSIZE cchString)
+static KU32 kFsCacheStrHashN(const char *pchString, KSIZE cchString)
 {
     KU32 uHash = 0;
     while (cchString-- > 0)
     {
-        KU32 uChar = (unsigned char)*pszString++;
+        KU32 uChar = (unsigned char)*pchString++;
         uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
     }
     return uHash;
@@ -587,6 +594,9 @@ PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
         pObj->abUnused[1]   = K_FALSE;
         pObj->fFlags        = pParent->Obj.fFlags & KFSOBJ_F_INHERITED_MASK;
         pObj->pParent       = pParent;
+        pObj->uNameHash     = 0;
+        pObj->pNextNameHash = NULL;
+        pObj->pNameAlloc    = NULL;
         pObj->pUserDataHead = NULL;
 
 #ifdef KFSCACHE_CFG_UTF16
@@ -636,7 +646,7 @@ PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
         kHlpAssert(pbExtra - (KU8 *)pObj == cbObj);
 
         /*
-         * Type specific initilization.
+         * Type specific initialization.
          */
         if (fDirish)
         {
@@ -644,8 +654,8 @@ PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
             pDirObj->cChildren          = 0;
             pDirObj->cChildrenAllocated = 0;
             pDirObj->papChildren        = NULL;
-            pDirObj->cHashTab           = 0;
-            pDirObj->paHashTab          = NULL;
+            pDirObj->fHashTabMask       = 0;
+            pDirObj->papHashTab         = NULL;
             pDirObj->hDir               = INVALID_HANDLE_VALUE;
             pDirObj->uDevNo             = pParent->uDevNo;
             pDirObj->iLastWrite         = 0;
@@ -794,11 +804,135 @@ static PKFSOBJ kFsCacheCreateMissingW(PKFSCACHE pCache, PKFSDIR pParent, const w
     return NULL;
 }
 
+
+/**
+ * Does the growing of names.
+ *
+ * @returns pCur
+ * @param   pCache          The cache.
+ * @param   pCur            The object.
+ * @param   pchName         The name (not necessarily terminated).
+ * @param   cchName         Name length.
+ * @param   pwcName         The UTF-16 name (not necessarily terminated).
+ * @param   cwcName         The length of the UTF-16 name in wchar_t's.
+ * @param   pchShortName    The short name.
+ * @param   cchShortName    The length of the short name.  This is 0 if no short
+ *                          name.
+ * @param   pwcShortName    The short UTF-16 name.
+ * @param   cwcShortName    The length of the short UTF-16 name.  This is 0 if
+ *                          no short name.
+ */
+static PKFSOBJ kFsCacheRefreshGrowNames(PKFSCACHE pCache, PKFSOBJ pCur,
+                                        const char *pchName, KU32 cchName,
+                                        wchar_t const *pwcName, KU32 cwcName
+#ifdef KFSCACHE_CFG_SHORT_NAMES
+                                        , const char *pchShortName, KU32 cchShortName,
+                                        wchar_t const *pwcShortName, KU32 cwcShortName
+#endif
+                                        )
+{
+    PKFSOBJNAMEALLOC    pNameAlloc;
+    char               *pch;
+    KU32                cbNeeded;
+
+    pCache->cNameGrowths++;
+
+    /*
+     * Figure out our requirements.
+     */
+    cbNeeded = sizeof(KU32) + cchName + 1;
+#ifdef KFSCACHE_CFG_UTF16
+    cbNeeded += (cwcName + 1) * sizeof(wchar_t);
+#endif
+#ifdef KFSCACHE_CFG_SHORT_NAMES
+    cbNeeded += cchShortName + !!cchShortName;
+# ifdef KFSCACHE_CFG_UTF16
+    cbNeeded += (cwcShortName + !!cwcShortName) * sizeof(wchar_t);
+# endif
+#endif
+    cbNeeded = K_ALIGN_Z(cbNeeded, 8); /* Memory will likely be 8 or 16 byte aligned, so we might just claim it. */
+
+    /*
+     * Allocate memory.
+     */
+    pNameAlloc = pCur->pNameAlloc;
+    if (!pNameAlloc)
+    {
+        pNameAlloc = (PKFSOBJNAMEALLOC)kHlpAlloc(cbNeeded);
+        if (!pNameAlloc)
+            return pCur;
+        pCache->cbObjects += cbNeeded;
+        pCur->pNameAlloc = pNameAlloc;
+        pNameAlloc->cb = cbNeeded;
+    }
+    else if (pNameAlloc->cb < cbNeeded)
+    {
+        pNameAlloc = (PKFSOBJNAMEALLOC)kHlpRealloc(pNameAlloc, cbNeeded);
+        if (!pNameAlloc)
+            return pCur;
+        pCache->cbObjects += cbNeeded - pNameAlloc->cb;
+        pCur->pNameAlloc = pNameAlloc;
+        pNameAlloc->cb = cbNeeded;
+    }
+
+    /*
+     * Copy out the new names, starting with the wide char ones to avoid misaligning them.
+     */
+    pch = &pNameAlloc->abSpace[0];
+
+#ifdef KFSCACHE_CFG_UTF16
+    pCur->pwszName = (wchar_t *)pch;
+    pCur->cwcName  = cwcName;
+    pch = kHlpMemPCopy(pch, pwcName, cwcName * sizeof(wchar_t));
+    *pch++ = '\0';
+    *pch++ = '\0';
+
+# ifdef KFSCACHE_CFG_SHORT_NAMES
+    if (cwcShortName == 0)
+    {
+        pCur->pwszShortName = pCur->pwszName;
+        pCur->cwcShortName  = pCur->cwcName;
+    }
+    else
+    {
+        pCur->pwszShortName = (wchar_t *)pch;
+        pCur->cwcShortName  = cwcShortName;
+        pch = kHlpMemPCopy(pch, pwcShortName, cwcShortName * sizeof(wchar_t));
+        *pch++ = '\0';
+        *pch++ = '\0';
+    }
+# endif
+#endif
+
+    pCur->pszName = pch;
+    pCur->cchName = cchName;
+    pch = kHlpMemPCopy(pch, pchName, cchShortName);
+    *pch++ = '\0';
+
+#ifdef KFSCACHE_CFG_SHORT_NAMES
+    if (cchShortName == 0)
+    {
+        pCur->pszShortName = pCur->pszName;
+        pCur->cchShortName = pCur->cchName;
+    }
+    else
+    {
+        pCur->pszShortName = pch;
+        pCur->cchShortName = cchShortName;
+        pch = kHlpMemPCopy(pch, pchShortName, cchShortName);
+        *pch++ = '\0';
+    }
+#endif
+
+    return pCur;
+}
+
+
 /**
  * Worker for kFsCacheDirFindOldChild that refreshes the file ID value on an
  * object found by name.
  *
- * @returns Pointer to the existing object if found, NULL if not.
+ * @returns pCur.
  * @param   pDirRePop       Repopulation data.
  * @param   pCur            The object to check the names of.
  * @param   idFile          The file ID.
@@ -818,7 +952,7 @@ static PKFSOBJ kFsCacheDirRefreshOldChildFileId(PKFSDIRREPOP pDirRePop, PKFSOBJ
  * Worker for kFsCacheDirFindOldChild that checks the names after an old object
  * has been found the file ID.
  *
- * @returns Pointer to the existing object if found, NULL if not.
+ * @returns pCur.
  * @param   pDirRePop       Repopulation data.
  * @param   pCur            The object to check the names of.
  * @param   pwcName         The file name.
@@ -832,11 +966,15 @@ static PKFSOBJ kFsCacheDirRefreshOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pC
 #endif
                                               )
 {
+    char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
+    int  cchName;
+
+    pDirRePop->pCache->cNameChanges++;
+
     /*
      * Convert the names to ANSI first, that way we know all the lengths.
      */
-    char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
-    int  cchName = WideCharToMultiByte(CP_ACP, 0, pwcName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
+    cchName = WideCharToMultiByte(CP_ACP, 0, pwcName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
     if (cchName >= 0)
     {
 #ifdef KFSCACHE_CFG_SHORT_NAMES
@@ -906,34 +1044,25 @@ static PKFSOBJ kFsCacheDirRefreshOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pC
                     return pCur;
                 }
             }
+
+            return kFsCacheRefreshGrowNames(pDirRePop->pCache, pCur, szName, cchName, pwcName, cwcName,
+#ifdef KFSCACHE_CFG_SHORT_NAMES
+                                            szShortName, cchShortName, pwcShortName, cwcShortName
+#endif
+                                            );
         }
     }
 
-
-    fprintf(stderr,
-            "kFsCacheDirRefreshOldChildName - not implemented!\n"
-            "  Old name:  %#x '%ls'\n"
-            "  New name:  %#x '%*.*ls'\n"
-            "  Old short: %#x '%ls'\n"
-            "  New short: %#x '%*.*ls'\n",
-            pCur->cwcName, pCur->pwszName,
-            cwcName, cwcName, cwcName, pwcName,
-            pCur->cwcShortName, pCur->pwszShortName,
-            cwcShortName, cwcShortName, cwcShortName, pwcShortName);
-    __debugbreak();
-    /** @todo implement this.  It's not entirely straight forward, especially if
-     *        the name increases!  Also, it's something that may happend during
-     *        individual object refresh and we might want to share code... */
-
+    fprintf(stderr, "kFsCacheDirRefreshOldChildName: WideCharToMultiByte error\n");
     return pCur;
 }
 
 
 /**
  * Worker for kFsCacheDirFindOldChild that checks the names after an old object
- * has been found the file ID.
+ * has been found by the file ID.
  *
- * @returns Pointer to the existing object if found, NULL if not.
+ * @returns pCur.
  * @param   pDirRePop       Repopulation data.
  * @param   pCur            The object to check the names of.
  * @param   pwcName         The file name.
@@ -1109,7 +1238,7 @@ K_INLINE PKFSOBJ kFsCacheDirFindOldChild(PKFSDIRREPOP pDirRePop, KI64 idFile, wc
     KU32 cOldChildren = pDirRePop->cOldChildren;
     if (cOldChildren > 0)
     {
-        KU32 const  iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren);
+        KU32 const  iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1);
         PKFSOBJ     pCur          = pDirRePop->papOldChildren[iNextOldChild];
 
         if (   pCur->Stats.st_ino == idFile
@@ -1252,8 +1381,23 @@ static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLO
      */
     else if (pDir->fPopulated)
     {
-        KU32  cAllocated = K_ALIGN_Z(pDir->cChildren, 16);
-        void *pvNew      = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated);
+        KU32  cAllocated;
+        void *pvNew;
+
+        /* Make sure we really need to do this first. */
+        if (!pDir->fNeedRePopulating)
+        {
+            if (   pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
+                || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
+                return K_TRUE;
+            if (   kFsCacheRefreshObj(pCache, &pDir->Obj, penmError)
+                && !pDir->fNeedRePopulating)
+                return K_TRUE;
+        }
+
+        /* Yes we do need to. */
+        cAllocated = K_ALIGN_Z(pDir->cChildren, 16);
+        pvNew      = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated);
         if (pvNew)
         {
             DirRePop.papOldChildren     = pDir->papChildren;
@@ -1515,6 +1659,23 @@ static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLO
                     KFSCACHE_LOG(("Refreshing %s/%s/ - %s was removed.\n",
                                   pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pOldChild->pszName));
                     kHlpAssert(pOldChild->bObjType != KFSOBJ_TYPE_DIR);
+                    /* Remove from hash table. */
+                    if (pOldChild->uNameHash != 0)
+                    {
+                        KU32    idx = pOldChild->uNameHash & pDir->fHashTabMask;
+                        PKFSOBJ pPrev = pDir->papHashTab[idx];
+                        if (pPrev == pOldChild)
+                            pDir->papHashTab[idx] = pOldChild->pNextNameHash;
+                        else
+                        {
+                            while (pPrev && pPrev->pNextNameHash != pOldChild)
+                                pPrev = pPrev->pNextNameHash;
+                            kHlpAssert(pPrev);
+                            if (pPrev)
+                                pPrev->pNextNameHash = pOldChild->pNextNameHash;
+                        }
+                        pOldChild->uNameHash = 0;
+                    }
                 }
                 kFsCacheObjRelease(pCache, pOldChild);
             }
@@ -1586,16 +1747,26 @@ static KBOOL kFsCacheDirIsModified(PKFSDIR pDir)
     if (   pDir->hDir != INVALID_HANDLE_VALUE
         && (pDir->Obj.fFlags & KFSOBJ_F_WORKING_DIR_MTIME) )
     {
-        MY_IO_STATUS_BLOCK          Ios;
-        MY_FILE_BASIC_INFORMATION   BasicInfo;
-        MY_NTSTATUS                 rcNt;
+        if (!pDir->fNeedRePopulating)
+        {
+            MY_IO_STATUS_BLOCK          Ios;
+            MY_FILE_BASIC_INFORMATION   BasicInfo;
+            MY_NTSTATUS                 rcNt;
 
-        Ios.Information = -1;
-        Ios.u.Status    = -1;
+            Ios.Information = -1;
+            Ios.u.Status    = -1;
 
-        rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
-        if (MY_NT_SUCCESS(rcNt))
-            return BasicInfo.LastWriteTime.QuadPart != pDir->iLastWrite;
+            rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
+            if (MY_NT_SUCCESS(rcNt))
+            {
+                if (BasicInfo.LastWriteTime.QuadPart != pDir->iLastWrite)
+                {
+                    pDir->fNeedRePopulating = K_TRUE;
+                    return K_TRUE;
+                }
+                return K_FALSE;
+            }
+        }
     }
     /* The cache root never changes. */
     else if (!pDir->Obj.pParent)
@@ -1810,6 +1981,7 @@ static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *
                     KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx and names too...\n",
                                   pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart));
                     fprintf(stderr, "kFsCacheRefreshObj - ID + name change not implemented!!\n");
+                    fflush(stderr);
                     __debugbreak();
                     pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart;
                     /** @todo implement as needed.   */
@@ -1895,6 +2067,7 @@ static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *
                 /* ouch! */
                 kHlpAssertMsgFailed(("%#x\n", rcNt));
                 fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on dir - not implemented!\n", rcNt);
+                fflush(stderr);
                 __debugbreak();
                 fRc = K_FALSE;
             }
@@ -1915,15 +2088,17 @@ static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *
  *          missing node.
  * @param   pCache              The cache.
  * @param   chLetter            The uppercased drive letter.
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  */
-static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPERROR *penmError)
+static PKFSOBJ kFsCacheLookupDrive(PKFSCACHE pCache, char chLetter, KU32 fFlags, KFSLOOKUPERROR *penmError)
 {
-    KU32 const          uHash = chLetter - 'A';
+    KU32 const          uNameHash = chLetter - 'A';
+    PKFSOBJ             pCur      = pCache->RootDir.papHashTab[uNameHash];
+
     KU32                cLeft;
     PKFSOBJ            *ppCur;
-
     MY_UNICODE_STRING   NtPath;
     wchar_t             wszTmp[8];
     char                szTmp[4];
@@ -1931,19 +2106,32 @@ static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPER
     /*
      * Custom drive letter hashing.
      */
-    if (pCache->RootDir.paHashTab)
+    kHlpAssert((uNameHash & pCache->RootDir.fHashTabMask) == uNameHash);
+    while (pCur)
     {
-        /** @todo PKFSOBJHASH pHash = */
+        if (   pCur->uNameHash == uNameHash
+            && pCur->cchName == 2
+            && pCur->pszName[0] == chLetter
+            && pCur->pszName[1] == ':')
+        {
+            if (pCur->bObjType == KFSOBJ_TYPE_DIR)
+                return pCur;
+            if (   (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
+                || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
+                return pCur;
+            return NULL;
+        }
+        pCur = pCur->pNextNameHash;
     }
 
     /*
-     * Special cased lookup.
+     * Make 100% sure it's not there.
      */
     cLeft = pCache->RootDir.cChildren;
     ppCur = pCache->RootDir.papChildren;
     while (cLeft-- > 0)
     {
-        PKFSOBJ pCur = *ppCur++;
+        pCur = *ppCur++;
         if (   pCur->cchName == 2
             && pCur->pszName[0] == chLetter
             && pCur->pszName[1] == ':')
@@ -1951,12 +2139,19 @@ static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPER
             if (pCur->bObjType == KFSOBJ_TYPE_DIR)
                 return pCur;
             kHlpAssert(pCur->bObjType == KFSOBJ_TYPE_MISSING);
-            if (kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
+            if (   (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
+                || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
                 return pCur;
             return NULL;
         }
     }
 
+    if (fFlags & KFSCACHE_LOOKUP_F_NO_INSERT)
+    {
+        *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; /* close enough */
+        return NULL;
+    }
+
     /*
      * Need to add it.  We always keep the drive letters open for the benefit
      * of kFsCachePopuplateOrRefreshDir and others.
@@ -1975,7 +2170,8 @@ static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPER
     {
         HANDLE      hDir;
         MY_NTSTATUS rcNt;
-        rcNt = birdOpenFileUniStr(&NtPath,
+        rcNt = birdOpenFileUniStr(NULL /*hRoot*/,
+                                  &NtPath,
                                   FILE_READ_DATA  | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                                   FILE_ATTRIBUTE_NORMAL,
                                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -2050,7 +2246,13 @@ static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPER
                  */
                 fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, &pDir->Obj, penmError);
                 kFsCacheObjRelease(pCache, &pDir->Obj);
-                return fRc ? &pDir->Obj : NULL;
+                if (fRc)
+                {
+                    pDir->Obj.pNextNameHash = pCache->RootDir.papHashTab[uNameHash];
+                    pCache->RootDir.papHashTab[uNameHash] = &pDir->Obj;
+                    return &pDir->Obj;
+                }
+                return NULL;
             }
 
             g_pfnNtClose(hDir);
@@ -2101,6 +2303,82 @@ static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPER
 
 
 /**
+ * Slow path that allocates the child hash table and enters the given one.
+ *
+ * Allocation fialures are ignored.
+ *
+ * @param   pCache              The cache (for stats).
+ * @param   pDir                The directory.
+ * @param   uNameHash           The name hash  to enter @a pChild under.
+ * @param   pChild              The child to enter into the hash table.
+ */
+static void kFsCacheDirAllocHashTabAndEnterChild(PKFSCACHE pCache, PKFSDIR pDir, KU32 uNameHash, PKFSOBJ pChild)
+{
+    if (uNameHash != 0) /* paranoia ^ 4! */
+    {
+        /*
+         * Double the current number of children and round up to a multiple of
+         * two so we can avoid division.
+         */
+        KU32 cbHashTab;
+        KU32 cEntries;
+        kHlpAssert(pDir->cChildren > 0);
+        if (pDir->cChildren <= KU32_MAX / 4)
+        {
+#if defined(_MSC_VER) && 1
+            KU32 cEntriesRaw = pDir->cChildren * 2;
+            KU32 cEntriesShift;
+            kHlpAssert(sizeof(cEntries) == (unsigned long));
+            if (_BitScanReverse(&cEntriesShift, cEntriesRaw))
+            {
+                if (   K_BIT32(cEntriesShift) < cEntriesRaw
+                    && cEntriesShift < 31U)
+                    cEntriesShift++;
+                cEntries = K_BIT32(cEntriesShift);
+            }
+            else
+            {
+                kHlpAssertFailed();
+                cEntries = KU32_MAX / 2 + 1;
+            }
+#else
+            cEntries = pDir->cChildren * 2 - 1;
+            cEntries |= cEntries >> 1;
+            cEntries |= cEntries >> 2;
+            cEntries |= cEntries >> 4;
+            cEntries |= cEntries >> 8;
+            cEntries |= cEntries >> 16;
+            cEntries++;
+#endif
+        }
+        else
+            cEntries = KU32_MAX / 2 + 1;
+        kHlpAssert((cEntries & (cEntries -  1)) == 0);
+
+        cbHashTab = cEntries * sizeof(pDir->papHashTab[0]);
+        pDir->papHashTab = (PKFSOBJ *)kHlpAllocZ(cbHashTab);
+        if (pDir->papHashTab)
+        {
+            KU32 idx;
+            pDir->fHashTabMask = cEntries - 1;
+            pCache->cbObjects += cbHashTab;
+            pCache->cChildHashTabs++;
+            pCache->cChildHashEntriesTotal += cEntries;
+
+            /*
+             * Insert it.
+             */
+            pChild->uNameHash     = uNameHash;
+            idx = uNameHash & (pDir->fHashTabMask);
+            pChild->pNextNameHash = pDir->papHashTab[idx];
+            pDir->papHashTab[idx] = pChild;
+            pCache->cChildHashed++;
+        }
+    }
+}
+
+
+/**
  * Look up a child node, ANSI version.
  *
  * @returns Pointer to the child if found, NULL if not.
@@ -2111,18 +2389,52 @@ static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPER
  */
 static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName)
 {
-    /* Check for '.' first. */
+    /*
+     * Check for '.' first ('..' won't appear).
+     */
     if (cchName != 1 || *pchName != '.')
     {
-        KU32        cLeft;
         PKFSOBJ    *ppCur;
+        KU32        cLeft;
+        KU32        uNameHash;
 
-        if (pParent->paHashTab != NULL)
+        /*
+         * Do hash table lookup.
+         *
+         * This caches previous lookups, which should be useful when looking up
+         * intermediate directories at least.
+         */
+        if (pParent->papHashTab != NULL)
         {
-            /** @todo directory hash table lookup.   */
+            PKFSOBJ pCur;
+            uNameHash = kFsCacheStrHashN(pchName, cchName);
+            pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask];
+            while (pCur)
+            {
+                if (   pCur->uNameHash == uNameHash
+                    && (   (   pCur->cchName == cchName
+                            && _mbsnicmp(pCur->pszName, pchName, cchName) == 0)
+#ifdef KFSCACHE_CFG_SHORT_NAMES
+                        || (   pCur->cchShortName == cchName
+                            && pCur->pszShortName != pCur->pszName
+                            && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0)
+#endif
+                        )
+                   )
+                {
+                    pCache->cChildHashHits++;
+                    pCache->cChildSearches++;
+                    return pCur;
+                }
+                pCur = pCur->pNextNameHash;
+            }
         }
+        else
+            uNameHash = 0;
 
-        /* Linear search. */
+        /*
+         * Do linear search.
+         */
         cLeft = pParent->cChildren;
         ppCur = pParent->papChildren;
         while (cLeft-- > 0)
@@ -2136,8 +2448,37 @@ static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char
                     && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0)
 #endif
                )
+            {
+                /*
+                 * Consider entering it into the parent hash table.
+                 * Note! We hash the input, not the name we found.
+                 */
+                if (   pCur->uNameHash == 0
+                    && pParent->cChildren >= 2)
+                {
+                    if (pParent->papHashTab)
+                    {
+                        if (uNameHash != 0)
+                        {
+                            KU32 idxNameHash = uNameHash & pParent->fHashTabMask;
+                            pCur->uNameHash     = uNameHash;
+                            pCur->pNextNameHash = pParent->papHashTab[idxNameHash];
+                            pParent->papHashTab[idxNameHash] = pCur;
+                            if (pCur->pNextNameHash)
+                                pCache->cChildHashCollisions++;
+                            pCache->cChildHashed++;
+                        }
+                    }
+                    else
+                        kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheStrHashN(pchName, cchName), pCur);
+                }
+
+                pCache->cChildSearches++;
                 return pCur;
+            }
         }
+
+        pCache->cChildSearches++;
         return NULL;
     }
     return &pParent->Obj;
@@ -2155,18 +2496,52 @@ static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char
  */
 static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName)
 {
-    /* Check for '.' first. */
+    /*
+     * Check for '.' first ('..' won't appear).
+     */
     if (cwcName != 1 || *pwcName != '.')
     {
-        KU32        cLeft;
         PKFSOBJ    *ppCur;
+        KU32        cLeft;
+        KU32        uNameHash;
 
-        if (pParent->paHashTab != NULL)
+        /*
+         * Do hash table lookup.
+         *
+         * This caches previous lookups, which should be useful when looking up
+         * intermediate directories at least.
+         */
+        if (pParent->papHashTab != NULL)
         {
-            /** @todo directory hash table lookup.   */
+            PKFSOBJ pCur;
+            uNameHash = kFsCacheUtf16HashN(pwcName, cwcName);
+            pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask];
+            while (pCur)
+            {
+                if (   pCur->uNameHash == uNameHash
+                    && (   (   pCur->cwcName == cwcName
+                            && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName))
+#ifdef KFSCACHE_CFG_SHORT_NAMES
+                         || (   pCur->cwcShortName == cwcName
+                             && pCur->pwszShortName != pCur->pwszName
+                             && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
+#endif
+                       )
+                   )
+                {
+                    pCache->cChildHashHits++;
+                    pCache->cChildSearches++;
+                    return pCur;
+                }
+                pCur = pCur->pNextNameHash;
+            }
         }
+        else
+            uNameHash = 0;
 
-        /* Linear search. */
+        /*
+         * Do linear search.
+         */
         cLeft = pParent->cChildren;
         ppCur = pParent->papChildren;
         while (cLeft-- > 0)
@@ -2180,8 +2555,36 @@ static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar
                     && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
 #endif
                )
+            {
+                /*
+                 * Consider entering it into the parent hash table.
+                 * Note! We hash the input, not the name we found.
+                 */
+                if (   pCur->uNameHash == 0
+                    && pParent->cChildren >= 4)
+                {
+                    if (pParent->papHashTab)
+                    {
+                        if (uNameHash != 0)
+                        {
+                            KU32 idxNameHash = uNameHash & pParent->fHashTabMask;
+                            pCur->uNameHash     = uNameHash;
+                            pCur->pNextNameHash = pParent->papHashTab[idxNameHash];
+                            pParent->papHashTab[idxNameHash] = pCur;
+                            if (pCur->pNextNameHash)
+                                pCache->cChildHashCollisions++;
+                            pCache->cChildHashed++;
+                        }
+                    }
+                    else
+                        kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheUtf16HashN(pwcName, cwcName), pCur);
+                }
+
+                pCache->cChildSearches++;
                 return pCur;
+            }
         }
+        pCache->cChildSearches++;
         return NULL;
     }
     return &pParent->Obj;
@@ -2198,12 +2601,30 @@ static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar
  *          node.
  * @param   pCache              The cache.
  * @param   pszPath             The path.
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   poff                Where to return the root dire.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  */
-static PKFSOBJ kFswCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 *poff, KFSLOOKUPERROR *penmError)
+static PKFSOBJ kFsCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 fFlags,
+                                       KU32 *poff, KFSLOOKUPERROR *penmError)
 {
+    /*
+     * Special case: Long path prefix w/ drive letter following it.
+     * Note! Must've been converted from wide char to ANSI.
+     */
+    if (   IS_SLASH(pszPath[0])
+        && IS_SLASH(pszPath[1])
+        && pszPath[2] == '?'
+        && IS_SLASH(pszPath[3])
+        && IS_ALPHA(pszPath[4])
+        && pszPath[5] == ':'
+        && IS_SLASH(pszPath[6]) )
+    {
+        *poff = 4 + 2;
+        return kFsCacheLookupDrive(pCache, pszPath[4], fFlags, penmError);
+    }
+
 #if 0 /* later */
     KU32 offStartServer;
     KU32 offEndServer;
@@ -2249,12 +2670,30 @@ static PKFSOBJ kFswCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, K
  *          node.
  * @param   pCache              The cache.
  * @param   pwszPath            The path.
- * @param   poff                Where to return the root dire.
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
+ * @param   poff                Where to return the root dir.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  */
-static PKFSOBJ kFswCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 *poff, KFSLOOKUPERROR *penmError)
+static PKFSOBJ kFsCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 fFlags,
+                                       KU32 *poff, KFSLOOKUPERROR *penmError)
 {
+    /*
+     * Special case: Long path prefix w/ drive letter following it.
+     */
+    if (   IS_SLASH(pwszPath[0])
+        && IS_SLASH(pwszPath[1])
+        && pwszPath[2] == '?'
+        && IS_SLASH(pwszPath[3])
+        && IS_ALPHA(pwszPath[4])
+        && pwszPath[5] == ':'
+        && IS_SLASH(pwszPath[6]) )
+    {
+        *poff = 4 + 2;
+        return kFsCacheLookupDrive(pCache, (char)pwszPath[4], fFlags, penmError);
+    }
+
+
 #if 0 /* later */
     KU32 offStartServer;
     KU32 offEndServer;
@@ -2303,13 +2742,14 @@ static PKFSOBJ kFswCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPat
  * @param   pParent             The directory to start the lookup in.
  * @param   pszPath             The path to walk.
  * @param   cchPath             The length of the path.
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  * @param   ppLastAncestor      Where to return the last parent element found
  *                              (referenced) in case of error an path/file not
  *                              found problem.  Optional.
  */
-PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath,
+PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags,
                                      KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
 {
     /*
@@ -2344,11 +2784,13 @@ PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const ch
         /*
          * Do we need to populate or refresh this directory first?
          */
-        if (   pParent->fPopulated
+        if (   !pParent->fNeedRePopulating
+            && pParent->fPopulated
             && (   pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
                 || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) )
         { /* likely */ }
-        else if (kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
+        else if (   (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH))
+                 || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
         { /* likely */ }
         else
             return NULL;
@@ -2364,7 +2806,8 @@ PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const ch
         { /* probably likely */ }
         else
         {
-            if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
+            if (    (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
+                && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT))
                 pChild = kFsCacheCreateMissingA(pCache, pParent, &pszPath[off], offEnd - off, penmError);
             if (cchSlashes == 0 || offEnd + cchSlashes >= cchPath)
             {
@@ -2387,6 +2830,7 @@ PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const ch
             if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
                 || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
                 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
+                || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
                 || kFsCacheRefreshMissing(pCache, pChild, penmError) )
             { /* likely */ }
             else
@@ -2408,7 +2852,8 @@ PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const ch
             return NULL;
         }
         else if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
-                 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
+                 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
+                 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH))
         {
             *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
             if (ppLastAncestor)
@@ -2443,13 +2888,14 @@ PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const ch
  * @param   pParent             The directory to start the lookup in.
  * @param   pszPath             The path to walk.  No dot-dot bits allowed!
  * @param   cchPath             The length of the path.
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  * @param   ppLastAncestor      Where to return the last parent element found
  *                              (referenced) in case of error an path/file not
  *                              found problem.  Optional.
  */
-PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath,
+PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
                                      KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
 {
     /*
@@ -2484,11 +2930,13 @@ PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wc
         /*
          * Do we need to populate or refresh this directory first?
          */
-        if (   pParent->fPopulated
+        if (   !pParent->fNeedRePopulating
+            && pParent->fPopulated
             && (   pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
                 || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) )
         { /* likely */ }
-        else if (kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
+        else if (   (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH))
+                 || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
         { /* likely */ }
         else
             return NULL;
@@ -2504,7 +2952,8 @@ PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wc
         { /* probably likely */ }
         else
         {
-            if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
+            if (    (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
+                && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT))
                 pChild = kFsCacheCreateMissingW(pCache, pParent, &pwszPath[off], offEnd - off, penmError);
             if (cwcSlashes == 0 || offEnd + cwcSlashes >= cwcPath)
             {
@@ -2527,6 +2976,7 @@ PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wc
             if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
                 || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
                 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
+                || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
                 || kFsCacheRefreshMissing(pCache, pChild, penmError) )
             { /* likely */ }
             else
@@ -2548,7 +2998,9 @@ PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wc
             return NULL;
         }
         else if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
-                 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
+                 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
+                 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) )
+
         {
             *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
             if (ppLastAncestor)
@@ -2582,13 +3034,14 @@ PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wc
  * @param   pCache              The cache.
  * @param   pszPath             The path to walk. No dot-dot bits allowed!
  * @param   cchPath             The length of the path.
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  * @param   ppLastAncestor      Where to return the last parent element found
  *                              (referenced) in case of error an path/file not
  *                              found problem.  Optional.
  */
-static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath,
+static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags,
                                        KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
 {
     PKFSOBJ     pRoot;
@@ -2608,11 +3061,11 @@ static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU
         /* Drive letter. */
         offEnd = 2;
         kHlpAssert(IS_SLASH(pszPath[2]));
-        pRoot = kFswCacheLookupDrive(pCache, toupper(pszPath[0]), penmError);
+        pRoot = kFsCacheLookupDrive(pCache, toupper(pszPath[0]), fFlags, penmError);
     }
     else if (   IS_SLASH(pszPath[0])
              && IS_SLASH(pszPath[1]) )
-        pRoot = kFswCacheLookupUncShareA(pCache, pszPath, &offEnd, penmError);
+        pRoot = kFsCacheLookupUncShareA(pCache, pszPath, fFlags, &offEnd, penmError);
     else
     {
         *penmError = KFSLOOKUPERROR_UNSUPPORTED;
@@ -2639,6 +3092,7 @@ static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU
             || pRoot->uCacheGen == (  pRoot->bObjType != KFSOBJ_TYPE_MISSING
                                     ? pCache->auGenerations[       pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
                                     : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
+            || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
             || kFsCacheRefreshObj(pCache, pRoot, penmError))
             return kFsCacheObjRetainInternal(pRoot);
         return NULL;
@@ -2660,7 +3114,7 @@ static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU
      * remainder of the path starting with it.
      */
     return kFsCacheLookupRelativeToDirA(pCache, (PKFSDIR)pRoot, &pszPath[offEnd + cchSlashes],
-                                        cchPath - offEnd - cchSlashes, penmError, ppLastAncestor);
+                                        cchPath - offEnd - cchSlashes, fFlags, penmError, ppLastAncestor);
 }
 
 
@@ -2676,13 +3130,14 @@ static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU
  * @param   pCache              The cache.
  * @param   pwszPath            The path to walk.
  * @param   cwcPath             The length of the path (in wchar_t's).
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  * @param   ppLastAncestor      Where to return the last parent element found
  *                              (referenced) in case of error an path/file not
  *                              found problem.  Optional.
  */
-static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath,
+static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
                                        KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
 {
     PKFSDIR     pParent = &pCache->RootDir;
@@ -2705,11 +3160,11 @@ static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath
         /* Drive letter. */
         offEnd = 2;
         kHlpAssert(IS_SLASH(pwszPath[2]));
-        pRoot = kFswCacheLookupDrive(pCache, toupper(pwszPath[0]), penmError);
+        pRoot = kFsCacheLookupDrive(pCache, toupper(pwszPath[0]), fFlags, penmError);
     }
     else if (   IS_SLASH(pwszPath[0])
              && IS_SLASH(pwszPath[1]) )
-        pRoot = kFswCacheLookupUncShareW(pCache, pwszPath, &offEnd, penmError);
+        pRoot = kFsCacheLookupUncShareW(pCache, pwszPath, fFlags, &offEnd, penmError);
     else
     {
         *penmError = KFSLOOKUPERROR_UNSUPPORTED;
@@ -2736,6 +3191,7 @@ static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath
             || pRoot->uCacheGen == (pRoot->bObjType != KFSOBJ_TYPE_MISSING
                                     ? pCache->auGenerations[       pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
                                     : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
+            || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
             || kFsCacheRefreshObj(pCache, pRoot, penmError))
             return kFsCacheObjRetainInternal(pRoot);
         return NULL;
@@ -2757,7 +3213,7 @@ static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath
      * remainder of the path starting with it.
      */
     return kFsCacheLookupRelativeToDirW(pCache, (PKFSDIR)pRoot, &pwszPath[offEnd + cwcSlashes],
-                                        cwcPath - offEnd - cwcSlashes, penmError, ppLastAncestor);
+                                        cwcPath - offEnd - cwcSlashes, fFlags, penmError, ppLastAncestor);
 }
 
 
@@ -2771,13 +3227,14 @@ static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath
  * @param   pCache              The cache.
  * @param   pszPath             The path.
  * @param   cchPath             The length of the path.
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  * @param   ppLastAncestor      Where to return the last parent element found
  *                              (referenced) in case of error an path/file not
  *                              found problem.  Optional.
  */
-static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath,
+static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags,
                                    KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
 {
     /*
@@ -2789,22 +3246,8 @@ static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 c
     if (   cchFull >= 3
         && cchFull < sizeof(szFull))
     {
-        PKFSOBJ pFsObj;
         KFSCACHE_LOG2(("kFsCacheLookupSlowA(%s)\n", pszPath));
-        pFsObj = kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, penmError, ppLastAncestor);
-
-#if 0 /* No need to do this until it's actually queried. */
-        /* Cache the resulting path. */
-        if (   pFsObj
-            || (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
-            || *penmError == KFSLOOKUPERROR_UNSUPPORTED)
-        {
-            KU32 uHashPath = kFsCacheStrHash(szFull);
-            kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath,
-                                            uHashPath % K_ELEMENTS(pCache->apAnsiPaths), *penmError);
-        }
-#endif
-        return pFsObj;
+        return kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, fFlags, penmError, ppLastAncestor);
     }
 
     /* The path is too long! */
@@ -2824,13 +3267,14 @@ static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 c
  * @param   pCache              The cache.
  * @param   pwszPath            The path.
  * @param   cwcPath             The length of the path (in wchar_t's).
+ * @param   fFlags              Lookup flags, KFSCACHE_LOOKUP_F_XXX.
  * @param   penmError           Where to return details as to why the lookup
  *                              failed.
  * @param   ppLastAncestor      Where to return the last parent element found
  *                              (referenced) in case of error an path/file not
  *                              found problem.  Optional.
  */
-static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath,
+static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath, KU32 fFlags,
                                    KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
 {
     /*
@@ -2842,22 +3286,8 @@ static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU
     if (   cwcFull >= 3
         && cwcFull < KFSCACHE_CFG_MAX_PATH)
     {
-        PKFSOBJ pFsObj;
         KFSCACHE_LOG2(("kFsCacheLookupSlowA(%ls)\n", pwszPath));
-        pFsObj = kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, penmError, ppLastAncestor);
-
-#if 0 /* No need to do this until it's actually queried. */
-        /* Cache the resulting path. */
-        if (   pFsObj
-            || (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
-            || *penmError == KFSLOOKUPERROR_UNSUPPORTED)
-        {
-            KU32 uHashPath = kFsCacheStrHash(szFull);
-            kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath,
-                                            uHashPath % K_ELEMENTS(pCache->apAnsiPaths), *penmError);
-        }
-#endif
-        return pFsObj;
+        return kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, fFlags, penmError, ppLastAncestor);
     }
 
     /* The path is too long! */
@@ -2881,10 +3311,10 @@ static PKFSHASHA kFsCacheRefreshPathA(PKFSCACHE pCache, PKFSHASHA pHashEntry, KU
     if (!pHashEntry->pFsObj)
     {
         if (pHashEntry->fAbsolute)
-            pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
+            pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
                                                          &pHashEntry->enmError, &pLastAncestor);
         else
-            pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
+            pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
                                                      &pHashEntry->enmError, &pLastAncestor);
     }
     else
@@ -2899,10 +3329,10 @@ static PKFSHASHA kFsCacheRefreshPathA(PKFSCACHE pCache, PKFSHASHA pHashEntry, KU
             {
                 kFsCacheObjRelease(pCache, pHashEntry->pFsObj);
                 if (pHashEntry->fAbsolute)
-                    pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
+                    pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
                                                                  &pHashEntry->enmError, &pLastAncestor);
                 else
-                    pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
+                    pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
                                                              &pHashEntry->enmError, &pLastAncestor);
             }
         }
@@ -2942,10 +3372,10 @@ static PKFSHASHW kFsCacheRefreshPathW(PKFSCACHE pCache, PKFSHASHW pHashEntry, KU
     if (!pHashEntry->pFsObj)
     {
         if (pHashEntry->fAbsolute)
-            pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
+            pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
                                                          &pHashEntry->enmError, &pLastAncestor);
         else
-            pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
+            pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
                                                      &pHashEntry->enmError, &pLastAncestor);
     }
     else
@@ -2960,16 +3390,17 @@ static PKFSHASHW kFsCacheRefreshPathW(PKFSCACHE pCache, PKFSHASHW pHashEntry, KU
             {
                 kFsCacheObjRelease(pCache, pHashEntry->pFsObj);
                 if (pHashEntry->fAbsolute)
-                    pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
+                    pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
                                                                  &pHashEntry->enmError, &pLastAncestor);
                 else
-                    pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
+                    pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
                                                              &pHashEntry->enmError, &pLastAncestor);
             }
         }
         else
         {
             fprintf(stderr, "kFsCacheRefreshPathW - refresh failure handling not implemented!\n");
+            fflush(stderr);
             __debugbreak();
             /** @todo just remove this entry.   */
             return NULL;
@@ -3068,12 +3499,12 @@ static PKFSOBJ kFsCacheLookupHashedA(PKFSCACHE pCache, const char *pchPath, KU32
                     && IS_SLASH(pchPath[1]) ) )
             && !kFsCacheHasDotDotA(pchPath, cchPath) )
         {
-            pFsObj = kFsCacheLookupAbsoluteA(pCache, pchPath, cchPath, penmError, &pLastAncestor);
+            pFsObj = kFsCacheLookupAbsoluteA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor);
             fAbsolute = K_TRUE;
         }
         else
         {
-            pFsObj = kFsCacheLookupSlowA(pCache, pchPath, cchPath, penmError, &pLastAncestor);
+            pFsObj = kFsCacheLookupSlowA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor);
             fAbsolute = K_FALSE;
         }
         if (   pFsObj
@@ -3176,12 +3607,12 @@ static PKFSOBJ kFsCacheLookupHashedW(PKFSCACHE pCache, const wchar_t *pwcPath, K
                     && IS_SLASH(pwcPath[1]) ) )
             && !kFsCacheHasDotDotW(pwcPath, cwcPath) )
         {
-            pFsObj = kFsCacheLookupAbsoluteW(pCache, pwcPath, cwcPath, penmError, &pLastAncestor);
+            pFsObj = kFsCacheLookupAbsoluteW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor);
             fAbsolute = K_TRUE;
         }
         else
         {
-            pFsObj = kFsCacheLookupSlowW(pCache, pwcPath, cwcPath, penmError, &pLastAncestor);
+            pFsObj = kFsCacheLookupSlowW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor);
             fAbsolute = K_FALSE;
         }
         if (   pFsObj
@@ -3369,18 +3800,21 @@ PKFSOBJ kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSL
  * @returns 0
  * @param   pCache              The cache.
  * @param   pObj                The object.
+ * @param   pszWhere            Where it was released from.
  */
-KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
+KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere)
 {
     kHlpAssert(pObj->cRefs == 0);
     kHlpAssert(pObj->pParent == NULL);
     kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
 
-    KFSCACHE_LOG(("Destroying %s/%s, type=%d\n", pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType));
+    KFSCACHE_LOG(("Destroying %s/%s, type=%d, pObj=%p, pszWhere=%s\n",
+                  pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType, pObj, pszWhere));
     if (pObj->abUnused[1] != 0)
     {
         fprintf(stderr, "Destroying %s/%s, type=%d, path hash entries: %d!\n", pObj->pParent ? pObj->pParent->Obj.pszName : "",
                 pObj->pszName, pObj->bObjType, pObj->abUnused[0]);
+        fflush(stderr);
         __debugbreak();
     }
 
@@ -3417,7 +3851,7 @@ KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
             KU32    cChildren = pDir->cChildren;
             pCache->cbObjects -= sizeof(*pDir)
                                + K_ALIGN_Z(cChildren, 16) * sizeof(pDir->papChildren)
-                               + pDir->cHashTab * sizeof(pDir->paHashTab);
+                               + (pDir->fHashTabMask + !!pDir->fHashTabMask) * sizeof(pDir->papHashTab[0]);
 
             pDir->cChildren   = 0;
             while (cChildren-- > 0)
@@ -3425,8 +3859,8 @@ KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
             kHlpFree(pDir->papChildren);
             pDir->papChildren = NULL;
 
-            kHlpFree(pDir->paHashTab);
-            pDir->paHashTab = NULL;
+            kHlpFree(pDir->papHashTab);
+            pDir->papHashTab = NULL;
             break;
         }
 
@@ -3457,6 +3891,12 @@ KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
 #endif
     pCache->cObjects--;
 
+    if (pObj->pNameAlloc)
+    {
+        pCache->cbObjects -= pObj->pNameAlloc->cb;
+        kHlpFree(pObj->pNameAlloc);
+    }
+
     kHlpFree(pObj);
     return 0;
 }
@@ -3469,6 +3909,7 @@ KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
  * @param   pCache              The cache.
  * @param   pObj                The object.
  */
+#undef kFsCacheObjRelease
 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj)
 {
     if (pObj)
@@ -3480,7 +3921,32 @@ KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj)
         cRefs = --pObj->cRefs;
         if (cRefs)
             return cRefs;
-        return kFsCacheObjDestroy(pCache, pObj);
+        return kFsCacheObjDestroy(pCache, pObj, "kFsCacheObjRelease");
+    }
+    return 0;
+}
+
+
+/**
+ * Debug version of kFsCacheObjRelease
+ *
+ * @returns New reference count.
+ * @param   pCache              The cache.
+ * @param   pObj                The object.
+ * @param   pszWhere            Where it's invoked from.
+ */
+KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere)
+{
+    if (pObj)
+    {
+        KU32 cRefs;
+        kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
+        kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
+
+        cRefs = --pObj->cRefs;
+        if (cRefs)
+            return cRefs;
+        return kFsCacheObjDestroy(pCache, pObj, pszWhere);
     }
     return 0;
 }
@@ -3983,6 +4449,64 @@ KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot)
 }
 
 
+/**
+ * Invalidates a deleted directory, ANSI version.
+ *
+ * @returns K_TRUE if found and is a non-root directory. Otherwise K_FALSE.
+ * @param   pCache              The cache.
+ * @param   pszDir              The directory.
+ */
+KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir)
+{
+    KU32            cchDir = (KU32)kHlpStrLen(pszDir);
+    KFSLOOKUPERROR  enmError;
+    PKFSOBJ         pFsObj;
+
+    /* Is absolute without any '..' bits? */
+    if (   cchDir >= 3
+        && (   (   pszDir[1] == ':'    /* Drive letter */
+                && IS_SLASH(pszDir[2])
+                && IS_ALPHA(pszDir[0]) )
+            || (   IS_SLASH(pszDir[0]) /* UNC */
+                && IS_SLASH(pszDir[1]) ) )
+        && !kFsCacheHasDotDotA(pszDir, cchDir) )
+        pFsObj = kFsCacheLookupAbsoluteA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH,
+                                         &enmError, NULL);
+    else
+        pFsObj = kFsCacheLookupSlowA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH,
+                                     &enmError, NULL);
+    if (pFsObj)
+    {
+        /* Is directory? */
+        if (pFsObj->bObjType == KFSOBJ_TYPE_DIR)
+        {
+            if (pFsObj->pParent != &pCache->RootDir)
+            {
+                PKFSDIR pDir = (PKFSDIR)pFsObj;
+                KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: %s hDir=%p\n", pszDir, pDir->hDir));
+                if (pDir->hDir != INVALID_HANDLE_VALUE)
+                {
+                    g_pfnNtClose(pDir->hDir);
+                    pDir->hDir = INVALID_HANDLE_VALUE;
+                }
+                pDir->fNeedRePopulating = K_TRUE;
+                pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN] - 1;
+                kFsCacheObjRetainInternal(&pDir->Obj);
+                return K_TRUE;
+            }
+            KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a root directory was deleted! %s\n", pszDir));
+        }
+        else
+            KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a non-directory: bObjType=%d %s\n",
+                          pFsObj->bObjType, pszDir));
+        kFsCacheObjRetainInternal(pFsObj);
+    }
+    else
+        KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: '%s' was not found\n", pszDir));
+    return K_FALSE;
+}
+
+
 PKFSCACHE kFsCacheCreate(KU32 fFlags)
 {
     PKFSCACHE pCache;
@@ -4021,29 +4545,37 @@ PKFSCACHE kFsCacheCreate(KU32 fFlags)
         pCache->RootDir.cChildrenAllocated  = 0;
         pCache->RootDir.papChildren         = NULL;
         pCache->RootDir.hDir                = INVALID_HANDLE_VALUE;
-        pCache->RootDir.cHashTab            = 251;
-        pCache->RootDir.paHashTab           = (PKFSOBJHASH)kHlpAllocZ(  pCache->RootDir.cHashTab
-                                                                      * sizeof(pCache->RootDir.paHashTab[0]));
-        if (pCache->RootDir.paHashTab)
+        pCache->RootDir.fHashTabMask        = 255; /* 256: 26 drive letters and 102 UNCs before we're half ways. */
+        pCache->RootDir.papHashTab          = (PKFSOBJ *)kHlpAllocZ(256 * sizeof(pCache->RootDir.papHashTab[0]));
+        if (pCache->RootDir.papHashTab)
         {
             /* The cache itself. */
-            pCache->u32Magic        = KFSCACHE_MAGIC;
-            pCache->fFlags          = fFlags;
+            pCache->u32Magic                = KFSCACHE_MAGIC;
+            pCache->fFlags                  = fFlags;
             pCache->auGenerations[0]        = KU32_MAX / 4;
             pCache->auGenerations[1]        = KU32_MAX / 32;
             pCache->auGenerationsMissing[0] = KU32_MAX / 256;
             pCache->auGenerationsMissing[1] = 1;
-            pCache->cObjects        = 1;
-            pCache->cbObjects       = sizeof(pCache->RootDir) + pCache->RootDir.cHashTab * sizeof(pCache->RootDir.paHashTab[0]);
-            pCache->cPathHashHits   = 0;
-            pCache->cWalkHits       = 0;
-            pCache->cAnsiPaths      = 0;
-            pCache->cAnsiPathCollisions = 0;
-            pCache->cbAnsiPaths     = 0;
+            pCache->cObjects                = 1;
+            pCache->cbObjects               = sizeof(pCache->RootDir)
+                                            + (pCache->RootDir.fHashTabMask + 1) * sizeof(pCache->RootDir.papHashTab[0]);
+            pCache->cPathHashHits           = 0;
+            pCache->cWalkHits               = 0;
+            pCache->cChildSearches          = 0;
+            pCache->cChildHashHits          = 0;
+            pCache->cChildHashed            = 0;
+            pCache->cChildHashTabs          = 1;
+            pCache->cChildHashEntriesTotal  = pCache->RootDir.fHashTabMask + 1;
+            pCache->cChildHashCollisions    = 0;
+            pCache->cNameChanges            = 0;
+            pCache->cNameGrowths            = 0;
+            pCache->cAnsiPaths              = 0;
+            pCache->cAnsiPathCollisions     = 0;
+            pCache->cbAnsiPaths             = 0;
 #ifdef KFSCACHE_CFG_UTF16
-            pCache->cUtf16Paths     = 0;
-            pCache->cUtf16PathCollisions = 0;
-            pCache->cbUtf16Paths    = 0;
+            pCache->cUtf16Paths             = 0;
+            pCache->cUtf16PathCollisions    = 0;
+            pCache->cbUtf16Paths            = 0;
 #endif
             return pCache;
         }
diff --git a/src/lib/nt/kFsCache.h b/src/lib/nt/kFsCache.h
index 2f306d7..e2d1bbe 100644
--- a/src/lib/nt/kFsCache.h
+++ b/src/lib/nt/kFsCache.h
@@ -1,4 +1,4 @@
-/* $Id: kFsCache.h 2868 2016-09-04 01:28:12Z bird $ */
+/* $Id: kFsCache.h 2967 2016-09-26 18:14:13Z bird $ */
 /** @file
  * kFsCache.c - NT directory content cache.
  */
@@ -47,7 +47,7 @@
 #define KFSCACHE_CFG_SHORT_NAMES            1
 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE
  * Size of the path hash table. */
-#define KFSCACHE_CFG_PATH_HASH_TAB_SIZE     16381
+#define KFSCACHE_CFG_PATH_HASH_TAB_SIZE     99991
 /** The max length paths we consider. */
 #define KFSCACHE_CFG_MAX_PATH               1024
 /** The max ANSI name length. */
@@ -111,20 +111,6 @@ typedef struct KFSDIR *PKFSDIR;
 typedef struct KFSOBJHASH *PKFSOBJHASH;
 
 
-/**
- * Directory hash table entry.
- *
- * There can be two of these per directory entry when the short name differs
- * from the long name.
- */
-typedef struct KFSOBJHASH
-{
-    /** Pointer to the next entry with the same hash. */
-    PKFSOBJHASH         pNext;
-    /** Pointer to the object. */
-    PKFSOBJ             pObj;
-} KFSOBJHASH;
-
 
 /** Pointer to a user data item. */
 typedef struct KFSUSERDATA *PKFSUSERDATA;
@@ -143,6 +129,21 @@ typedef struct KFSUSERDATA
 
 
 /**
+ * Storage for name strings for the unlikely event that they should grow in
+ * length after the KFSOBJ was created.
+ */
+typedef struct KFSOBJNAMEALLOC
+{
+    /** Size of the allocation. */
+    KU32        cb;
+    /** The space for names. */
+    char        abSpace[1];
+} KFSOBJNAMEALLOC;
+/** Name growth allocation. */
+typedef KFSOBJNAMEALLOC *PKFSOBJNAMEALLOC;
+
+
+/**
  * Base cache node.
  */
 typedef struct KFSOBJ
@@ -162,6 +163,17 @@ typedef struct KFSOBJ
     /** Flags, KFSOBJ_F_XXX. */
     KU32                fFlags;
 
+    /** Hash value of the name inserted into the parent hash table.
+     * This is 0 if not inserted.  Names are only hashed and inserted as they are
+     * first found thru linear searching of its siblings, and which name it is
+     * dependens on the lookup function (W or A) and whether the normal name or
+     * short name seems to have matched.
+     *
+     * @note It was ruled out as too much work to hash and track all four names,
+     *       so instead this minimalist approach was choosen in stead. */
+    KU32                uNameHash;
+    /** Pointer to the next child with the same name hash value. */
+    PKFSOBJ             pNextNameHash;
     /** Pointer to the parent (directory).
      * This is only NULL for a root. */
     PKFSDIR             pParent;
@@ -204,6 +216,9 @@ typedef struct KFSOBJ
 # endif
 #endif
 
+    /** Allocation for handling name length increases. */
+    PKFSOBJNAMEALLOC    pNameAlloc;
+
     /** Pointer to the first user data item */
     PKFSUSERDATA        pUserDataHead;
 
@@ -230,13 +245,16 @@ typedef struct KFSDIR
     /** The allocated size of papChildren. */
     KU32                cChildrenAllocated;
 
-    /** Pointer to the hash table.
-     * @todo this isn't quite there yet, structure wise. sigh.  */
-    PKFSOBJHASH         paHashTab;
-    /** The size of the hash table.
-     * @remarks The hash table is optional and only used when there are a lot of
-     *          entries in the directory. */
-    KU32                cHashTab;
+    /** Pointer to the child hash table. */
+    PKFSOBJ            *papHashTab;
+    /** The mask shift of the hash table.
+     * Hash table size is a power of two, this is the size minus one.
+     *
+     * @remarks The hash table is optional and populated by lookup hits.  The
+     *          assumption being that a lookup is repeated and will choose a good
+     *          name to hash on.  We've got up to 4 different hashes, so this
+     *          was the easy way out. */
+    KU32                fHashTabMask;
 
     /** Handle to the directory (we generally keep it open). */
 #ifndef DECLARE_HANDLE
@@ -400,6 +418,23 @@ typedef struct KFSCACHE
     KSIZE               cPathHashHits;
     /** Number of hits walking the file system hierarchy. */
     KSIZE               cWalkHits;
+    /** Number of child searches. */
+    KSIZE               cChildSearches;
+    /** Number of cChildLookups resolved thru hash table hits. */
+    KSIZE               cChildHashHits;
+    /** The number of child hash tables. */
+    KSIZE               cChildHashTabs;
+    /** The sum of all child hash table sizes. */
+    KSIZE               cChildHashEntriesTotal;
+    /** Number of children inserted into the hash tables. */
+    KSIZE               cChildHashed;
+    /** Number of collisions in the child hash tables. */
+    KSIZE               cChildHashCollisions;
+    /** Number times a object name changed. */
+    KSIZE               cNameChanges;
+    /** Number times a object name grew and needed KFSOBJNAMEALLOC.
+     *  (Subset of cNameChanges) */
+    KSIZE               cNameGrowths;
 
     /** The root directory. */
     KFSDIR              RootDir;
@@ -456,17 +491,29 @@ PKFSOBJ     kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t con
                                   KU8 bObjType, KFSLOOKUPERROR *penmError);
 PKFSOBJ     kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError);
 PKFSOBJ     kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError);
-PKFSOBJ     kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath,
+PKFSOBJ     kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags,
                                          KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor);
-PKFSOBJ     kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath,
+PKFSOBJ     kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
                                          KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor);
 PKFSOBJ     kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError);
 PKFSOBJ     kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError);
 PKFSOBJ     kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError);
 PKFSOBJ     kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError);
 
+/** @name KFSCACHE_LOOKUP_F_XXX - lookup flags
+ * @{ */
+/** No inserting new cache entries.
+ * This effectively prevent directories from being repopulated too.  */
+#define KFSCACHE_LOOKUP_F_NO_INSERT     KU32_C(1)
+/** No refreshing cache entries. */
+#define KFSCACHE_LOOKUP_F_NO_REFRESH    KU32_C(2)
+/** @} */
 
 KU32        kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
+KU32        kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere);
+#ifndef NDEBUG /* enable to debug object release. */
+# define kFsCacheObjRelease(a_pCache, a_pObj) kFsCacheObjReleaseTagged(a_pCache, a_pObj, __FUNCTION__)
+#endif
 KU32        kFsCacheObjRetain(PKFSOBJ pObj);
 PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData);
 PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey);
@@ -484,5 +531,6 @@ void        kFsCacheInvalidateAll(PKFSCACHE pCache);
 void        kFsCacheInvalidateCustomMissing(PKFSCACHE pCache);
 void        kFsCacheInvalidateCustomBoth(PKFSCACHE pCache);
 KBOOL       kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot);
+KBOOL       kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir);
 
 #endif
diff --git a/src/lib/nt/ntdir.c b/src/lib/nt/ntdir.c
index a80e53a..3ea166e 100644
--- a/src/lib/nt/ntdir.c
+++ b/src/lib/nt/ntdir.c
@@ -1,10 +1,10 @@
-/* $Id: ntdir.c 2708 2013-11-21 10:26:40Z bird $ */
+/* $Id: ntdir.c 2985 2016-11-01 18:26:35Z bird $ */
 /** @file
  * MSC + NT opendir, readdir, telldir, seekdir, and closedir.
  */
 
 /*
- * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ * Copyright (c) 2005-2016 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -35,6 +35,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <malloc.h>
+#include <assert.h>
 
 #include "ntstuff.h"
 #include "nthlp.h"
@@ -42,61 +43,103 @@
 
 
 /**
- * Internal worker for birdStatModTimeOnly.
+ * Implements opendir.
  */
-static BirdDir_T *birdDirOpenInternal(const char *pszPath, const char *pszFilter, int fMinimalInfo)
+BirdDir_T *birdDirOpen(const char *pszPath)
 {
-    HANDLE hFile = birdOpenFile(pszPath,
-                                FILE_READ_DATA | SYNCHRONIZE,
-                                FILE_ATTRIBUTE_NORMAL,
-                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                                FILE_OPEN,
-                                FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
-                                OBJ_CASE_INSENSITIVE);
-    if (hFile != INVALID_HANDLE_VALUE)
+    HANDLE hDir = birdOpenFile(pszPath,
+                               FILE_READ_DATA | SYNCHRONIZE,
+                               FILE_ATTRIBUTE_NORMAL,
+                               FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                               FILE_OPEN,
+                               FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+                               OBJ_CASE_INSENSITIVE);
+    if (hDir != INVALID_HANDLE_VALUE)
     {
-        /*
-         * Allocate a handle.
-         */
-        BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir));
+        BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE);
         if (pDir)
-        {
-            pDir->uMagic     = BIRD_DIR_MAGIC;
-            pDir->pvHandle   = (void *)hFile;
-            pDir->uDev       = 0;
-            pDir->offPos     = 0;
-            pDir->fHaveData  = 0;
-            pDir->fFirst     = 1;
-            pDir->iInfoClass = fMinimalInfo ? MyFileNamesInformation : MyFileIdFullDirectoryInformation;
-            pDir->offBuf     = 0;
-            pDir->cbBuf      = 0;
-            pDir->pabBuf     = NULL;
             return pDir;
-        }
-
-        birdCloseFile(hFile);
-        birdSetErrnoToNoMem();
+        birdCloseFile(hDir);
     }
-
     return NULL;
 }
 
 
 /**
- * Implements opendir.
+ * Alternative opendir, with extra stat() info returned by readdir().
  */
-BirdDir_T *birdDirOpen(const char *pszPath)
+BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)
 {
-    return birdDirOpenInternal(pszPath, NULL, 1 /*fMinimalInfo*/);
+    HANDLE hDir = birdOpenFile(pszPath,
+                               FILE_READ_DATA | SYNCHRONIZE,
+                               FILE_ATTRIBUTE_NORMAL,
+                               FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                               FILE_OPEN,
+                               FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+                               OBJ_CASE_INSENSITIVE);
+    if (hDir != INVALID_HANDLE_VALUE)
+    {
+        BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE | BIRDDIR_F_EXTRA_INFO);
+        if (pDir)
+            return pDir;
+        birdCloseFile(hDir);
+    }
+    return NULL;
+}
+
+
+BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags)
+{
+    HANDLE hDir = birdOpenFileExW((HANDLE)hRoot,
+                                  pwszPath,
+                                  FILE_READ_DATA | SYNCHRONIZE,
+                                  FILE_ATTRIBUTE_NORMAL,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                  FILE_OPEN,
+                                  FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+                                  OBJ_CASE_INSENSITIVE);
+    if (hDir != INVALID_HANDLE_VALUE)
+    {
+        BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, pwszFilter, fFlags | BIRDDIR_F_CLOSE_HANDLE);
+        if (pDir)
+            return pDir;
+        birdCloseFile(hDir);
+    }
+    return NULL;
 }
 
 
 /**
- * Alternative opendir, with extra stat() info returned by readdir().
+ * Internal worker for birdStatModTimeOnly.
  */
-BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)
+BirdDir_T *birdDirOpenFromHandle(void *pvHandle, const void *pvReserved, unsigned fFlags)
 {
-    return birdDirOpenInternal(pszPath, NULL, 0 /*fMinimalInfo*/);
+    if (!pvReserved)
+    {
+        /*
+         * Allocate and initialize the directory enum handle.
+         */
+        BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir));
+        if (pDir)
+        {
+            pDir->uMagic        = BIRD_DIR_MAGIC;
+            pDir->fFlags        = fFlags;
+            pDir->pvHandle      = pvHandle;
+            pDir->uDev          = 0;
+            pDir->offPos        = 0;
+            pDir->fHaveData     = 0;
+            pDir->fFirst        = 1;
+            pDir->iInfoClass    = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation;
+            pDir->offBuf        = 0;
+            pDir->cbBuf         = 0;
+            pDir->pabBuf        = NULL;
+            return pDir;
+        }
+    }
+    else
+        assert(pvReserved == NULL);
+    birdSetErrnoToNoMem();
+    return NULL;
 }
 
 
@@ -157,7 +200,7 @@ static int birdDirReadMore(BirdDir_T *pDir)
                                      (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass,
                                      FALSE,     /* fReturnSingleEntry */
                                      NULL,      /* Filter / restart pos. */
-                                     FALSE);    /* fRestartScan */
+                                     pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */
     if (!MY_NT_SUCCESS(rcNt))
     {
         int rc;
@@ -172,6 +215,7 @@ static int birdDirReadMore(BirdDir_T *pDir)
 
     pDir->offBuf    = 0;
     pDir->fHaveData = 1;
+    pDir->fFlags    &= ~BIRDDIR_F_RESTART_SCAN;
 
     return 0;
 }
@@ -354,7 +398,8 @@ int             birdDirClose(BirdDir_T *pDir)
         return birdSetErrnoToBadFileNo();
 
     pDir->uMagic++;
-    birdCloseFile((HANDLE)pDir->pvHandle);
+    if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE)
+        birdCloseFile((HANDLE)pDir->pvHandle);
     pDir->pvHandle = (void *)INVALID_HANDLE_VALUE;
     birdMemFree(pDir->pabBuf);
     pDir->pabBuf = NULL;
diff --git a/src/lib/nt/ntdir.h b/src/lib/nt/ntdir.h
index f84cf51..dd8eee2 100644
--- a/src/lib/nt/ntdir.h
+++ b/src/lib/nt/ntdir.h
@@ -1,4 +1,4 @@
-/* $Id: ntdir.h 2708 2013-11-21 10:26:40Z bird $ */
+/* $Id: ntdir.h 2985 2016-11-01 18:26:35Z bird $ */
 /** @file
  * MSC + NT opendir, readdir, closedir and friends.
  */
@@ -64,10 +64,24 @@ typedef struct dirent
 #define DT_WHT              14
 /** @}  */
 
+/** @name BIRDDIR_F_XXX - birdDirOpenFromHandle & BirdDir_T::fFlags
+ * @{ */
+/** birdDirClose should also close pvHandle.  */
+#define BIRDDIR_F_CLOSE_HANDLE  1U
+/** birdDirClose should not close the handle.  */
+#define BIRDDIR_F_KEEP_HANDLE   0U
+/** Provide extra info (stat). */
+#define BIRDDIR_F_EXTRA_INFO    2U
+/** Whether to restart the scan. */
+#define BIRDDIR_F_RESTART_SCAN  4U
+/** @} */
+
 typedef struct BirdDir
 {
     /** Magic value. */
     unsigned            uMagic;
+    /** Flags. */
+    unsigned            fFlags;
     /** The directory handle. */
     void               *pvHandle;
     /** The device number (st_dev). */
@@ -97,6 +111,8 @@ typedef struct BirdDir
 
 BirdDir_T      *birdDirOpen(const char *pszPath);
 BirdDir_T      *birdDirOpenExtraInfo(const char *pszPath);
+BirdDir_T      *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags);
+BirdDir_T      *birdDirOpenFromHandle(void *hDir, const void *pvReserved, unsigned fFlags);
 BirdDirEntry_T *birdDirRead(BirdDir_T *pDir);
 long            birdDirTell(BirdDir_T *pDir);
 void            birdDirSeek(BirdDir_T *pDir, long offDir);
diff --git a/src/lib/nt/nthlp.h b/src/lib/nt/nthlp.h
index 467daaf..4199cc2 100644
--- a/src/lib/nt/nthlp.h
+++ b/src/lib/nt/nthlp.h
@@ -1,4 +1,4 @@
-/* $Id: nthlp.h 2862 2016-09-02 02:39:56Z bird $ */
+/* $Id: nthlp.h 2997 2016-11-01 23:28:02Z bird $ */
 /** @file
  * MSC + NT helper functions.
  */
@@ -54,16 +54,27 @@ int         birdSetErrnoToInvalidArg(void);
 int         birdSetErrnoToBadFileNo(void);
 
 
-HANDLE      birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
-                         ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
-HANDLE      birdOpenParentDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
-                              ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+HANDLE      birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                         ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
+HANDLE      birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                          ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
+HANDLE      birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                           ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
+HANDLE      birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                            ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
+HANDLE      birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                              ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
                               MY_UNICODE_STRING *pNameUniStr);
-MY_NTSTATUS birdOpenFileUniStr(MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+HANDLE      birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                               ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+                               MY_UNICODE_STRING *pNameUniStr);
+MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
                                ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
                                HANDLE *phFile);
+HANDLE      birdOpenCurrentDirectory(void);
 void        birdCloseFile(HANDLE hFile);
 int         birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath);
+int         birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath);
 void        birdFreeNtPath(MY_UNICODE_STRING *pNtPath);
 
 
diff --git a/src/lib/nt/nthlpcore.c b/src/lib/nt/nthlpcore.c
index a6e0d7e..b4d77eb 100644
--- a/src/lib/nt/nthlpcore.c
+++ b/src/lib/nt/nthlpcore.c
@@ -1,4 +1,4 @@
-/* $Id: nthlpcore.c 2862 2016-09-02 02:39:56Z bird $ */
+/* $Id: nthlpcore.c 2985 2016-11-01 18:26:35Z bird $ */
 /** @file
  * MSC + NT core helpers functions and globals.
  */
@@ -45,6 +45,8 @@ MY_NTSTATUS (WINAPI *g_pfnNtClose)(HANDLE);
 MY_NTSTATUS (WINAPI *g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *,
                                         PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
 MY_NTSTATUS (WINAPI *g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *);
+MY_NTSTATUS (WINAPI *g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet,
+                                             MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions);
 MY_NTSTATUS (WINAPI *g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx,
                                       MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile,
                                       PULONG puKey);
@@ -61,6 +63,9 @@ MY_NTSTATUS (WINAPI *g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_
 BOOLEAN     (WINAPI *g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *, MY_UNICODE_STRING const *, BOOLEAN);
 BOOLEAN     (WINAPI *g_pfnRtlEqualString)(MY_ANSI_STRING const *, MY_ANSI_STRING const *, BOOLEAN);
 UCHAR       (WINAPI *g_pfnRtlUpperChar)(UCHAR uch);
+ULONG       (WINAPI *g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt);
+VOID        (WINAPI *g_pfnRtlAcquirePebLock)(VOID);
+VOID        (WINAPI *g_pfnRtlReleasePebLock)(VOID);
 
 
 static struct
@@ -72,6 +77,7 @@ static struct
     { (FARPROC *)&g_pfnNtClose,                         "NtClose" },
     { (FARPROC *)&g_pfnNtCreateFile,                    "NtCreateFile" },
     { (FARPROC *)&g_pfnNtDeleteFile,                    "NtDeleteFile" },
+    { (FARPROC *)&g_pfnNtDuplicateObject,               "NtDuplicateObject" },
     { (FARPROC *)&g_pfnNtReadFile,                      "NtReadFile" },
     { (FARPROC *)&g_pfnNtQueryInformationFile,          "NtQueryInformationFile" },
     { (FARPROC *)&g_pfnNtQueryVolumeInformationFile,    "NtQueryVolumeInformationFile" },
@@ -84,6 +90,9 @@ static struct
     { (FARPROC *)&g_pfnRtlEqualUnicodeString,           "RtlEqualUnicodeString" },
     { (FARPROC *)&g_pfnRtlEqualString,                  "RtlEqualString" },
     { (FARPROC *)&g_pfnRtlUpperChar,                    "RtlUpperChar" },
+    { (FARPROC *)&g_pfnRtlNtStatusToDosError,           "RtlNtStatusToDosError" },
+    { (FARPROC *)&g_pfnRtlAcquirePebLock,               "RtlAcquirePebLock" },
+    { (FARPROC *)&g_pfnRtlReleasePebLock,               "RtlReleasePebLock" },
 };
 /** Set to 1 if we've successfully resolved the imports, otherwise 0. */
 int g_fResolvedNtImports = 0;
@@ -155,7 +164,6 @@ int birdErrnoFromNtStatus(MY_NTSTATUS rcNt)
     {
         /* EPERM            =  1 */
         case STATUS_CANNOT_DELETE:
-        case STATUS_DELETE_PENDING:
             return EPERM;
         /* ENOENT           =  2 */
         case STATUS_NOT_FOUND:
@@ -172,6 +180,7 @@ int birdErrnoFromNtStatus(MY_NTSTATUS rcNt)
         case STATUS_BAD_NETWORK_PATH:
         case STATUS_DFS_EXIT_PATH_FOUND:
         case RPC_NT_OBJECT_NOT_FOUND:
+        case STATUS_DELETE_PENDING:
             return ENOENT;
         /* ESRCH            =  3 */
         case STATUS_PROCESS_NOT_IN_JOB:
@@ -377,6 +386,13 @@ int birdErrnoFromNtStatus(MY_NTSTATUS rcNt)
 int birdSetErrnoFromNt(MY_NTSTATUS rcNt)
 {
     errno = birdErrnoFromNtStatus(rcNt);
+#if 0
+    {
+        ULONG rcWin32;
+        _doserrno = rcWin32 = g_pfnRtlNtStatusToDosError(rcNt);
+        SetLastError(rcWin32);
+    }
+#endif
     return -1;
 }
 
diff --git a/src/lib/nt/nthlpfs.c b/src/lib/nt/nthlpfs.c
index d2e7f45..c51fe07 100644
--- a/src/lib/nt/nthlpfs.c
+++ b/src/lib/nt/nthlpfs.c
@@ -1,4 +1,4 @@
-/* $Id: nthlpfs.c 2713 2013-11-21 21:11:00Z bird $ */
+/* $Id: nthlpfs.c 2997 2016-11-01 23:28:02Z bird $ */
 /** @file
  * MSC + NT helpers for file system related functions.
  */
@@ -33,6 +33,10 @@
 *   Header Files                                                               *
 *******************************************************************************/
 #include "nthlp.h"
+#include <stddef.h>
+#include <string.h>
+#include <wchar.h>
+#include <errno.h>
 
 
 /*******************************************************************************
@@ -60,6 +64,24 @@ static int birdHasTrailingSlash(const char *pszPath)
 }
 
 
+static int birdHasTrailingSlashW(const wchar_t *pwszPath)
+{
+    wchar_t wc, wc2;
+
+    /* Skip leading slashes. */
+    while ((wc = *pwszPath) == '/' || wc == '\\')
+        pwszPath++;
+    if (wc == '\0')
+        return 0;
+
+    /* Find the last char. */
+    while ((wc2 = *++pwszPath) != '\0')
+        wc = wc2;
+
+    return wc == '/' || wc == '\\' || wc == ':';
+}
+
+
 static int birdIsPathDirSpec(const char *pszPath)
 {
     char ch, ch2;
@@ -77,6 +99,23 @@ static int birdIsPathDirSpec(const char *pszPath)
 }
 
 
+static int birdIsPathDirSpecW(const wchar_t *pwszPath)
+{
+    wchar_t wc, wc2;
+
+    /* Check for empty string. */
+    wc = *pwszPath;
+    if (wc == '\0')
+        return 0;
+
+    /* Find the last char. */
+    while ((wc2 = *++pwszPath) != '\0')
+        wc = wc2;
+
+    return wc == '/' || wc == '\\' || wc == ':';
+}
+
+
 int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath)
 {
     MY_NTSTATUS         rcNt;
@@ -118,6 +157,129 @@ int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath)
 }
 
 
+int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath)
+{
+    birdResolveImports();
+
+    pNtPath->Length = pNtPath->MaximumLength = 0;
+    pNtPath->Buffer = NULL;
+
+    /*
+     * Convert the wide DOS path to an NT path.
+     */
+    if (g_pfnRtlDosPathNameToNtPathName_U(pwszPath, pNtPath, NULL, FALSE))
+        return 0;
+    return birdSetErrnoFromNt(STATUS_NO_MEMORY);
+}
+
+
+/**
+ * Converts UNIX slashes to DOS ones.
+ *
+ * @returns 0
+ * @param   pNtPath     The relative NT path to fix up.
+ */
+static int birdFixRelativeNtPathSlashesAndReturn0(MY_UNICODE_STRING *pNtPath)
+{
+    size_t   cwcLeft  = pNtPath->Length / sizeof(wchar_t);
+    wchar_t *pwcStart = pNtPath->Buffer;
+    wchar_t *pwcHit;
+
+    /* Convert slashes. */
+    while ((pwcHit = wmemchr(pwcStart,  '/', cwcLeft)) != NULL)
+    {
+        *pwcHit = '\\';
+        cwcLeft -= pwcHit - pwcStart;
+        pwcHit = pwcStart;
+    }
+
+#if 0
+    /* Strip trailing slashes (NT doesn't like them). */
+    while (   pNtPath->Length >= sizeof(wchar_t)
+           && pNtPath->Buffer[(pNtPath->Length - sizeof(wchar_t)) / sizeof(wchar_t)] == '\\')
+    {
+        pNtPath->Length -= sizeof(wchar_t);
+        pNtPath->Buffer[pNtPath->Length / sizeof(wchar_t)] = '\0';
+    }
+
+    /* If it was all trailing slashes we convert it to a dot path. */
+    if (   pNtPath->Length == 0
+        && pNtPath->MaximumLength >= sizeof(wchar_t) * 2)
+    {
+        pNtPath->Length = sizeof(wchar_t);
+        pNtPath->Buffer[0] = '.';
+        pNtPath->Buffer[1] = '\0';
+    }
+#endif
+
+    return 0;
+}
+
+
+/**
+ * Similar to birdDosToNtPath, but it does call RtlDosPathNameToNtPathName_U.
+ *
+ * @returns 0 on success, -1 + errno on failure.
+ * @param   pszPath     The relative path.
+ * @param   pNtPath     Where to return the NT path.  Call birdFreeNtPath when done.
+ */
+int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath)
+{
+    MY_NTSTATUS         rcNt;
+    MY_ANSI_STRING      Src;
+
+    birdResolveImports();
+
+    /*
+     * Just convert to wide char.
+     */
+    pNtPath->Length   = pNtPath->MaximumLength = 0;
+    pNtPath->Buffer   = NULL;
+
+    Src.Buffer        = (PCHAR)pszPath;
+    Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath);
+
+    rcNt = g_pfnRtlAnsiStringToUnicodeString(pNtPath, &Src, TRUE /* Allocate */);
+    if (MY_NT_SUCCESS(rcNt))
+        return birdFixRelativeNtPathSlashesAndReturn0(pNtPath);
+    return birdSetErrnoFromNt(rcNt);
+}
+
+
+/**
+ * Similar to birdDosToNtPathW, but it does call RtlDosPathNameToNtPathName_U.
+ *
+ * @returns 0 on success, -1 + errno on failure.
+ * @param   pwszPath    The relative path.
+ * @param   pNtPath     Where to return the NT path.  Call birdFreeNtPath when done.
+ */
+int birdDosToRelativeNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath)
+{
+    size_t cwcPath = wcslen(pwszPath);
+    if (cwcPath < 0xfffe)
+    {
+        pNtPath->Length = (USHORT)(cwcPath * sizeof(wchar_t));
+        pNtPath->MaximumLength = pNtPath->Length + sizeof(wchar_t);
+        pNtPath->Buffer = HeapAlloc(GetProcessHeap(), 0, pNtPath->MaximumLength);
+        if (pNtPath->Buffer)
+        {
+            memcpy(pNtPath->Buffer, pwszPath, pNtPath->MaximumLength);
+            return birdFixRelativeNtPathSlashesAndReturn0(pNtPath);
+        }
+        errno = ENOMEM;
+    }
+    else
+        errno = ENAMETOOLONG;
+    return -1;
+}
+
+
+/**
+ * Frees a string returned by birdDosToNtPath, birdDosToNtPathW or
+ * birdDosToRelativeNtPath.
+ *
+ * @param   pNtPath             The the NT path to free.
+ */
 void birdFreeNtPath(MY_UNICODE_STRING *pNtPath)
 {
     HeapFree(GetProcessHeap(), 0, pNtPath->Buffer);
@@ -127,7 +289,7 @@ void birdFreeNtPath(MY_UNICODE_STRING *pNtPath)
 }
 
 
-MY_NTSTATUS birdOpenFileUniStr(MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
                                ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
                                HANDLE *phFile)
 {
@@ -143,7 +305,7 @@ MY_NTSTATUS birdOpenFileUniStr(MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredA
 
     Ios.Information = -1;
     Ios.u.Status = 0;
-    MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, NULL /*hRoot*/, NULL /*pSecAttr*/);
+    MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, hRoot, NULL /*pSecAttr*/);
 
     rcNt = g_pfnNtCreateFile(phFile,
                              fDesiredAccess,
@@ -184,8 +346,8 @@ MY_NTSTATUS birdOpenFileUniStr(MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredA
 }
 
 
-HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
-                    ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
+HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                    ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
 {
     MY_UNICODE_STRING   NtPath;
     MY_NTSTATUS         rcNt;
@@ -197,20 +359,46 @@ HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFile
         fCreateOptions |= FILE_DIRECTORY_FILE;
 
     /*
-     * Call the NT API directly.
+     * Convert the path and call birdOpenFileUniStr to do the real work.
      */
     if (birdDosToNtPath(pszPath, &NtPath) == 0)
     {
         HANDLE hFile;
-        rcNt = birdOpenFileUniStr(&NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
+        rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
                                   fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
+        birdFreeNtPath(&NtPath);
         if (MY_NT_SUCCESS(rcNt))
-        {
-            birdFreeNtPath(&NtPath);
             return hFile;
-        }
+        birdSetErrnoFromNt(rcNt);
+    }
 
+    return INVALID_HANDLE_VALUE;
+}
+
+
+HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                     ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
+{
+    MY_UNICODE_STRING   NtPath;
+    MY_NTSTATUS         rcNt;
+
+    /*
+     * Adjust inputs.
+     */
+    if (birdIsPathDirSpecW(pwszPath))
+        fCreateOptions |= FILE_DIRECTORY_FILE;
+
+    /*
+     * Convert the path and call birdOpenFileUniStr to do the real work.
+     */
+    if (birdDosToNtPathW(pwszPath, &NtPath) == 0)
+    {
+        HANDLE hFile;
+        rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
+                                  fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
         birdFreeNtPath(&NtPath);
+        if (MY_NT_SUCCESS(rcNt))
+            return hFile;
         birdSetErrnoFromNt(rcNt);
     }
 
@@ -218,9 +406,8 @@ HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFile
 }
 
 
-HANDLE birdOpenParentDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
-                         ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
-                         MY_UNICODE_STRING *pNameUniStr)
+HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                      ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
 {
     MY_UNICODE_STRING   NtPath;
     MY_NTSTATUS         rcNt;
@@ -228,76 +415,219 @@ HANDLE birdOpenParentDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG
     /*
      * Adjust inputs.
      */
-    fCreateOptions |= FILE_DIRECTORY_FILE;
+    if (birdIsPathDirSpec(pszPath))
+        fCreateOptions |= FILE_DIRECTORY_FILE;
 
     /*
-     * Convert the path and split off the filename.
+     * Convert the path and call birdOpenFileUniStr to do the real work.
      */
-    if (birdDosToNtPath(pszPath, &NtPath) == 0)
+    if (hRoot == INVALID_HANDLE_VALUE)
+        hRoot = NULL;
+    if ((hRoot != NULL ? birdDosToRelativeNtPath(pszPath, &NtPath) : birdDosToNtPath(pszPath, &NtPath)) == 0)
     {
-        USHORT offName = NtPath.Length / sizeof(WCHAR);
-        USHORT cwcName = offName;
-        WCHAR  wc = 0;
-
-        while (   offName > 0
-               && (wc = NtPath.Buffer[offName - 1]) != '\\'
-               && wc != '/'
-               && wc != ':')
-            offName--;
-        if (offName > 0)
-        {
-            cwcName -= offName;
+        HANDLE hFile;
+        rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
+                                  fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
+        birdFreeNtPath(&NtPath);
+        if (MY_NT_SUCCESS(rcNt))
+            return hFile;
+        birdSetErrnoFromNt(rcNt);
+    }
+
+    return INVALID_HANDLE_VALUE;
+}
+
+
+HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                       ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
+{
+    MY_UNICODE_STRING   NtPath;
+    MY_NTSTATUS         rcNt;
+
+    /*
+     * Adjust inputs.
+     */
+    if (birdIsPathDirSpecW(pwszPath))
+        fCreateOptions |= FILE_DIRECTORY_FILE;
+
+    /*
+     * Convert the path (could save ourselves this if pwszPath is perfect) and
+     * call birdOpenFileUniStr to do the real work.
+     */
+    if (hRoot == INVALID_HANDLE_VALUE)
+        hRoot = NULL;
+    if ((hRoot != NULL ? birdDosToRelativeNtPathW(pwszPath, &NtPath) : birdDosToNtPathW(pwszPath, &NtPath)) == 0)
+    {
+        HANDLE hFile;
+        rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
+                                  fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
+        birdFreeNtPath(&NtPath);
+        if (MY_NT_SUCCESS(rcNt))
+            return hFile;
+        birdSetErrnoFromNt(rcNt);
+    }
+
+    return INVALID_HANDLE_VALUE;
+}
 
-            /* Make a copy of the file name, if requested. */
-            rcNt = STATUS_SUCCESS;
-            if (pNameUniStr)
+
+static HANDLE birdOpenParentDirCommon(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                                      ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+                                      MY_UNICODE_STRING *pNameUniStr)
+{
+    MY_NTSTATUS rcNt;
+
+    /*
+     * Strip the path down to the directory.
+     */
+    USHORT offName = pNtPath->Length / sizeof(WCHAR);
+    USHORT cwcName = offName;
+    WCHAR  wc = 0;
+    while (   offName > 0
+           && (wc = pNtPath->Buffer[offName - 1]) != '\\'
+           && wc != '/'
+           && wc != ':')
+        offName--;
+    if (   offName > 0
+        || (hRoot != NULL && cwcName > 0))
+    {
+        cwcName -= offName;
+
+        /* Make a copy of the file name, if requested. */
+        rcNt = STATUS_SUCCESS;
+        if (pNameUniStr)
+        {
+            pNameUniStr->Length        = cwcName * sizeof(WCHAR);
+            pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR);
+            pNameUniStr->Buffer        = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength);
+            if (pNameUniStr->Buffer)
             {
-                pNameUniStr->Length        = cwcName * sizeof(WCHAR);
-                pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR);
-                pNameUniStr->Buffer        = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength);
-                if (pNameUniStr->Buffer)
-                {
-                    memcpy(pNameUniStr->Buffer, &NtPath.Buffer[offName],pNameUniStr->Length);
-                    pNameUniStr->Buffer[cwcName] = '\0';
-                }
-                else
-                    rcNt = STATUS_NO_MEMORY;
+                memcpy(pNameUniStr->Buffer, &pNtPath->Buffer[offName], pNameUniStr->Length);
+                pNameUniStr->Buffer[cwcName] = '\0';
             }
+            else
+                rcNt = STATUS_NO_MEMORY;
+        }
 
-            /* Chop, chop. */
-            // Bad idea, breaks \\?\c:\pagefile.sys. //while (   offName > 0
-            // Bad idea, breaks \\?\c:\pagefile.sys. //       && (   (wc = NtPath.Buffer[offName - 1]) == '\\'
-            // Bad idea, breaks \\?\c:\pagefile.sys. //           || wc == '/'))
-            // Bad idea, breaks \\?\c:\pagefile.sys. //    offName--;
-            NtPath.Length = offName * sizeof(WCHAR);
-            NtPath.Buffer[offName] = '\0';
+        /* Chop, chop. */
+        // Bad idea, breaks \\?\c:\pagefile.sys. //while (   offName > 0
+        // Bad idea, breaks \\?\c:\pagefile.sys. //       && (   (wc = pNtPath->Buffer[offName - 1]) == '\\'
+        // Bad idea, breaks \\?\c:\pagefile.sys. //           || wc == '/'))
+        // Bad idea, breaks \\?\c:\pagefile.sys. //    offName--;
+        if (offName == 0)
+            pNtPath->Buffer[offName++] = '.'; /* Hack for dir handle + dir entry name. */
+        pNtPath->Length = offName * sizeof(WCHAR);
+        pNtPath->Buffer[offName] = '\0';
+        if (MY_NT_SUCCESS(rcNt))
+        {
+            /*
+             * Finally, try open the directory.
+             */
+            HANDLE hFile;
+            fCreateOptions |= FILE_DIRECTORY_FILE;
+            rcNt = birdOpenFileUniStr(hRoot, pNtPath, fDesiredAccess, fFileAttribs, fShareAccess,
+                                      fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
             if (MY_NT_SUCCESS(rcNt))
             {
-                /*
-                 * Finally, try open the directory.
-                 */
-                HANDLE hFile;
-                rcNt = birdOpenFileUniStr(&NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
-                                          fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
-                if (MY_NT_SUCCESS(rcNt))
-                {
-                    birdFreeNtPath(&NtPath);
-                    return hFile;
-                }
+                birdFreeNtPath(pNtPath);
+                return hFile;
             }
-
-            if (pNameUniStr)
-                birdFreeNtPath(pNameUniStr);
         }
 
-        birdFreeNtPath(&NtPath);
-        birdSetErrnoFromNt(rcNt);
+        if (pNameUniStr)
+            birdFreeNtPath(pNameUniStr);
     }
+    else
+        rcNt = STATUS_INVALID_PARAMETER;
+
+    birdFreeNtPath(pNtPath);
+    birdSetErrnoFromNt(rcNt);
+    return INVALID_HANDLE_VALUE;
+}
+
+
+HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                         ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+                         MY_UNICODE_STRING *pNameUniStr)
+{
+    /*
+     * Convert the path and join up with the UTF-16 version (it'll free NtPath).
+     */
+    MY_UNICODE_STRING NtPath;
+    if (hRoot == INVALID_HANDLE_VALUE)
+        hRoot = NULL;
+    if (  hRoot == NULL
+        ? birdDosToNtPath(pszPath, &NtPath) == 0
+        : birdDosToRelativeNtPath(pszPath, &NtPath) == 0)
+        return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
+                                       fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr);
+    return INVALID_HANDLE_VALUE;
+}
+
 
+HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
+                          ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+                          MY_UNICODE_STRING *pNameUniStr)
+{
+    /*
+     * Convert the path and join up with the ansi version (it'll free NtPath).
+     */
+    MY_UNICODE_STRING NtPath;
+    if (hRoot == INVALID_HANDLE_VALUE)
+        hRoot = NULL;
+    if (  hRoot == NULL
+        ? birdDosToNtPathW(pwszPath, &NtPath) == 0
+        : birdDosToRelativeNtPathW(pwszPath, &NtPath) == 0)
+        return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
+                                       fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr);
     return INVALID_HANDLE_VALUE;
 }
 
 
+/**
+ * Returns a handle to the current working directory of the process.
+ *
+ * @returns CWD handle with FILE_TRAVERSE and SYNCHRONIZE access.  May return
+ *          INVALID_HANDLE_VALUE w/ errno for invalid CWD.
+ */
+HANDLE birdOpenCurrentDirectory(void)
+{
+    PMY_RTL_USER_PROCESS_PARAMETERS pProcParams;
+    MY_NTSTATUS rcNt;
+    HANDLE hRet = INVALID_HANDLE_VALUE;
+
+    birdResolveImports();
+
+    /*
+     * We'll try get this from the PEB.
+     */
+    g_pfnRtlAcquirePebLock();
+    pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)MY_NT_CURRENT_PEB()->ProcessParameters;
+    if (pProcParams != NULL)
+        rcNt = g_pfnNtDuplicateObject(MY_NT_CURRENT_PROCESS, pProcParams->CurrentDirectory.Handle,
+                                      MY_NT_CURRENT_PROCESS, &hRet,
+                                      FILE_TRAVERSE | SYNCHRONIZE,
+                                      0 /*fAttribs*/,
+                                      0 /*fOptions*/);
+    else
+        rcNt = STATUS_INVALID_PARAMETER;
+    g_pfnRtlReleasePebLock();
+    if (MY_NT_SUCCESS(rcNt))
+        return hRet;
+
+    /*
+     * Fallback goes thru birdOpenFileW.
+     */
+    return birdOpenFileW(L".",
+                         FILE_TRAVERSE | SYNCHRONIZE,
+                         FILE_ATTRIBUTE_NORMAL,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE,
+                         FILE_OPEN,
+                         FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+                         OBJ_CASE_INSENSITIVE);
+}
+
+
 void birdCloseFile(HANDLE hFile)
 {
     birdResolveImports();
diff --git a/src/lib/nt/ntstat.c b/src/lib/nt/ntstat.c
index 0c85692..8778cda 100644
--- a/src/lib/nt/ntstat.c
+++ b/src/lib/nt/ntstat.c
@@ -1,4 +1,4 @@
-/* $Id: ntstat.c 2880 2016-09-05 20:36:26Z bird $ */
+/* $Id: ntstat.c 2993 2016-11-01 22:41:26Z bird $ */
 /** @file
  * MSC + NT stat, lstat and fstat.
  */
@@ -45,12 +45,24 @@
 
 static int birdIsExecutableExtension(const char *pszExt)
 {
-    return  !strcmp(pszExt, "exe")
-         || !strcmp(pszExt, "cmd")
-         || !strcmp(pszExt, "bat")
-         || !strcmp(pszExt, "vbs")
-         || !strcmp(pszExt, "com")
-         ;
+    switch (pszExt[0])
+    {
+        default:
+            return 0;
+
+        case 'e': /* exe */
+            return pszExt[1] == 'x' && pszExt[2] == 'e' && pszExt[3] == '\0';
+
+        case 'b': /* bat */
+            return pszExt[1] == 'a' && pszExt[2] == 't' && pszExt[3] == '\0';
+
+        case 'v': /* vbs */
+            return pszExt[1] == 'v' && pszExt[2] == 's' && pszExt[3] == '\0';
+
+        case 'c': /* com and cmd */
+            return (pszExt[1] == 'o' && pszExt[2] == 'm' && pszExt[3] == '\0')
+                || (pszExt[1] == 'm' && pszExt[2] == 'd' && pszExt[3] == '\0');
+    }
 }
 
 
@@ -78,12 +90,16 @@ static int birdIsFileExecutable(const char *pszName)
     if (cchExt != 3)
         return 0;
 
-    /* Copy the extension out and lower case it. */
+    /* Copy the extension out and lower case it.  Fail immediately on non-alpha chars. */
     for (i = 0; i < cchExt; i++, pszExt++)
     {
         ch = *pszExt;
-        if (ch >= 'A' && ch <= 'Z')
+        if (ch >= 'a' && ch <= 'z')
+        { /* likely */ }
+        else if (ch >= 'A' && ch <= 'Z')
             ch += 'a' - 'A';
+        else
+            return 0;
         szExt[i] = ch;
     }
     szExt[i] = '\0';
@@ -92,7 +108,10 @@ static int birdIsFileExecutable(const char *pszName)
 }
 
 
-static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName)
+/**
+ * @a pwcName could be the full path.
+ */
+static int birdIsFileExecutableW(WCHAR const *pwcName, size_t cwcName)
 {
     char            szExt[8];
     unsigned        cchExt;
@@ -109,15 +128,17 @@ static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName)
     else
         return 0;
 
-    /* Copy the extension out and lower case it. */
+    /* Copy the extension out and lower case it.  Fail immediately on non-alpha chars. */
     pwc = &pwcName[cwcName - cchExt];
     for (i = 0; i < cchExt; i++, pwc++)
     {
         WCHAR wc = *pwc;
-        if (wc >= 'A' && wc <= 'Z')
+        if (wc >= 'a' && wc <= 'z')
+        { /* likely */ }
+        else if (wc >= 'A' && wc <= 'Z')
             wc += 'a' - 'A';
-        else if (wc > 255)
-            wc = 255;
+        else
+            return 0;
         szExt[i] = (char)wc;
     }
     szExt[i] = '\0';
@@ -127,7 +148,7 @@ static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName)
 
 
 static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName,
-                                         MY_FILE_NAME_INFORMATION *pNameInfo, __int16 *pfIsDirSymlink)
+                                         const wchar_t *pwszName, size_t cbNameW, __int16 *pfIsDirSymlink)
 {
     unsigned short fMode;
 
@@ -166,9 +187,9 @@ static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const cha
     if (!(fAttribs & FILE_ATTRIBUTE_READONLY))
         fMode |= S_IWOTH | S_IWGRP | S_IWUSR;
     if (   (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
-        || (pszName
-            ? birdIsFileExecutable(pszName)
-            : birdIsFileExecutableW(pNameInfo->FileName, pNameInfo->FileNameLength)) )
+        || (pwszName
+            ? birdIsFileExecutableW(pwszName, cbNameW)
+            : birdIsFileExecutable(pszName)) )
         fMode |= S_IXOTH | S_IXGRP | S_IXUSR;
 
     return fMode;
@@ -185,8 +206,8 @@ static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const cha
  */
 void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
 {
-    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
-                                                 NULL, &pStat->st_dirsymlink);
+    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
+                                                 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
     pStat->st_padding0[0]   = 0;
     pStat->st_padding0[1]   = 0;
     pStat->st_size          = pBuf->EndOfFile.QuadPart;
@@ -217,8 +238,8 @@ void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_IN
  */
 void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
 {
-    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
-                                                 NULL, &pStat->st_dirsymlink);
+    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
+                                                 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
     pStat->st_padding0[0]   = 0;
     pStat->st_padding0[1]   = 0;
     pStat->st_size          = pBuf->EndOfFile.QuadPart;
@@ -249,8 +270,8 @@ void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_IN
  */
 void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
 {
-    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
-                                                 NULL, &pStat->st_dirsymlink);
+    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
+                                                 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
     pStat->st_padding0[0]   = 0;
     pStat->st_padding0[1]   = 0;
     pStat->st_size          = pBuf->EndOfFile.QuadPart;
@@ -271,7 +292,7 @@ void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMA
 }
 
 
-int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
+int birdStatHandle2(HANDLE hFile, BirdStat_T *pStat, const char *pszPath, const wchar_t *pwszPath)
 {
     int                      rc;
     MY_NTSTATUS              rcNt;
@@ -289,7 +310,8 @@ int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
         if (MY_NT_SUCCESS(rcNt))
         {
             pStat->st_mode          = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
-                                                         &pAll->NameInformation, &pStat->st_dirsymlink);
+                                                         pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength,
+                                                         &pStat->st_dirsymlink);
             pStat->st_padding0[0]   = 0;
             pStat->st_padding0[1]   = 0;
             pStat->st_size          = pAll->StandardInformation.EndOfFile.QuadPart;
@@ -351,7 +373,7 @@ int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
         rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
     if (MY_NT_SUCCESS(rcNt))
         rcNt = Ios.u.Status;
-    if (MY_NT_SUCCESS(rcNt) && !pszPath)
+    if (MY_NT_SUCCESS(rcNt) && !pszPath && !pwszPath)
     {
         cbNameInfo = 0x10020;
         pNameInfo  = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
@@ -363,7 +385,10 @@ int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
     if (MY_NT_SUCCESS(rcNt))
     {
         pStat->st_mode          = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
-                                                     pNameInfo, &pStat->st_dirsymlink);
+                                                     pNameInfo ? pNameInfo->FileName : pwszPath,
+                                                     pNameInfo ? pNameInfo->FileNameLength
+                                                     : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0,
+                                                     &pStat->st_dirsymlink);
         pStat->st_padding0[0]   = 0;
         pStat->st_padding0[1]   = 0;
         pStat->st_size          = StdInfo.EndOfFile.QuadPart;
@@ -412,6 +437,12 @@ int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
 }
 
 
+int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
+{
+    return birdStatHandle2(hFile, pStat, pszPath, NULL);
+}
+
+
 /**
  * Generates a device number from the volume information.
  *
@@ -459,19 +490,19 @@ MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMAT
 }
 
 
-static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
+static int birdStatInternal(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollow)
 {
     int rc;
-    HANDLE hFile = birdOpenFile(pszPath,
-                                FILE_READ_ATTRIBUTES,
-                                FILE_ATTRIBUTE_NORMAL,
-                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                                FILE_OPEN,
-                                FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
-                                OBJ_CASE_INSENSITIVE);
+    HANDLE hFile = birdOpenFileEx(hRoot, pszPath,
+                                  FILE_READ_ATTRIBUTES,
+                                  FILE_ATTRIBUTE_NORMAL,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                  FILE_OPEN,
+                                  FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
+                                  OBJ_CASE_INSENSITIVE);
     if (hFile != INVALID_HANDLE_VALUE)
     {
-        rc = birdStatHandle(hFile, pStat, pszPath);
+        rc = birdStatHandle2(hFile, pStat, pszPath, NULL);
         birdCloseFile(hFile);
 
 #if 0
@@ -499,7 +530,7 @@ static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
             && strchr(pszPath, '?') == NULL)
         {
             MY_UNICODE_STRING NameUniStr;
-            hFile = birdOpenParentDir(pszPath,
+            hFile = birdOpenParentDir(hRoot, pszPath,
                                       FILE_READ_DATA | SYNCHRONIZE,
                                       FILE_ATTRIBUTE_NORMAL,
                                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -551,6 +582,84 @@ static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
 }
 
 
+static int birdStatInternalW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollow)
+{
+    int rc;
+    HANDLE hFile = birdOpenFileExW(hRoot, pwszPath,
+                                   FILE_READ_ATTRIBUTES,
+                                   FILE_ATTRIBUTE_NORMAL,
+                                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                   FILE_OPEN,
+                                   FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
+                                   OBJ_CASE_INSENSITIVE);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        rc = birdStatHandle2(hFile, pStat, NULL, pwszPath);
+        birdCloseFile(hFile);
+    }
+    else
+    {
+        /*
+         * On things like pagefile.sys we may get sharing violation.  We fall
+         * back on directory enumeration for dealing with that.
+         */
+        if (   errno == ETXTBSY
+            && wcschr(pwszPath, '*') == NULL /* Serious paranoia... */
+            && wcschr(pwszPath, '?') == NULL)
+        {
+            MY_UNICODE_STRING NameUniStr;
+            hFile = birdOpenParentDirW(hRoot, pwszPath,
+                                       FILE_READ_DATA | SYNCHRONIZE,
+                                       FILE_ATTRIBUTE_NORMAL,
+                                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                       FILE_OPEN,
+                                       FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+                                       OBJ_CASE_INSENSITIVE,
+                                       &NameUniStr);
+            if (hFile != INVALID_HANDLE_VALUE)
+            {
+                MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
+                ULONG               cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
+                MY_IO_STATUS_BLOCK  Ios;
+                MY_NTSTATUS         rcNt;
+
+                pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
+                Ios.u.Status    = -1;
+                Ios.Information = -1;
+                rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
+                                                 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
+                if (MY_NT_SUCCESS(rcNt))
+                    rcNt = Ios.u.Status;
+                if (MY_NT_SUCCESS(rcNt))
+                {
+                    /*
+                     * Convert the data.
+                     */
+                    birdStatFillFromFileIdFullDirInfo(pStat, pBuf, NULL);
+
+                    /* Get the serial number, reusing the buffer from above. */
+                    rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev);
+                    if (MY_NT_SUCCESS(rcNt))
+                        rc = 0;
+                    else
+                        rc = birdSetErrnoFromNt(rcNt);
+                }
+
+                birdFreeNtPath(&NameUniStr);
+                birdCloseFile(hFile);
+
+                if (MY_NT_SUCCESS(rcNt))
+                    return 0;
+                birdSetErrnoFromNt(rcNt);
+            }
+        }
+        rc = -1;
+    }
+
+    return rc;
+}
+
+
 /**
  * Implements UNIX fstat().
  */
@@ -569,7 +678,7 @@ int birdStatOnFd(int fd, BirdStat_T *pStat)
         switch (fFileType)
         {
             case FILE_TYPE_DISK:
-                rc = birdStatHandle(hFile, pStat, NULL);
+                rc = birdStatHandle2(hFile, pStat, NULL, NULL);
                 break;
 
             case FILE_TYPE_CHAR:
@@ -656,7 +765,16 @@ int birdStatOnFdJustSize(int fd, __int64 *pcbFile)
  */
 int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
 {
-    return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
+    return birdStatInternal(NULL, pszPath, pStat, 1 /*fFollow*/);
+}
+
+
+/**
+ * Implements UNIX stat().
+ */
+int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat)
+{
+    return birdStatInternalW(NULL, pwszPath, pStat, 1 /*fFollow*/);
 }
 
 
@@ -665,7 +783,46 @@ int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
  */
 int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
 {
-    return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
+    return birdStatInternal(NULL, pszPath, pStat, 0 /*fFollow*/);
+}
+
+
+/**
+ * Implements UNIX lstat().
+ */
+int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat)
+{
+    return birdStatInternalW(NULL, pwszPath, pStat, 0 /*fFollow*/);
+}
+
+
+/**
+ * Implements an API like UNIX fstatat().
+ *
+ * @returns 0 on success, -1 and errno on failure.
+ * @param   hRoot               NT handle pwszPath is relative to.
+ * @param   pszPath             The path.
+ * @param   pStat               Where to return stats.
+ * @param   fFollowLink         Whether to follow links.
+ */
+int birdStatAt(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink)
+{
+    return birdStatInternal(hRoot, pszPath, pStat, fFollowLink != 0);
+}
+
+
+/**
+ * Implements an API like UNIX fstatat().
+ *
+ * @returns 0 on success, -1 and errno on failure.
+ * @param   hRoot               NT handle pwszPath is relative to.
+ * @param   pwszPath            The path.
+ * @param   pStat               Where to return stats.
+ * @param   fFollowLink         Whether to follow links.
+ */
+int birdStatAtW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink)
+{
+    return birdStatInternalW(hRoot, pwszPath, pStat, fFollowLink != 0);
 }
 
 
diff --git a/src/lib/nt/ntstat.h b/src/lib/nt/ntstat.h
index 35bd4b4..ca18c3b 100644
--- a/src/lib/nt/ntstat.h
+++ b/src/lib/nt/ntstat.h
@@ -1,4 +1,4 @@
-/* $Id: ntstat.h 2858 2016-09-01 15:12:24Z bird $ */
+/* $Id: ntstat.h 2985 2016-11-01 18:26:35Z bird $ */
 /** @file
  * MSC + NT stat, lstat and fstat implementation and wrappers.
  */
@@ -76,7 +76,11 @@ typedef struct BirdStat
 #define st_birthtime    st_birthtim.tv_sec
 
 int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat);
+int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat);
 int birdStatOnLink(const char *pszPath, BirdStat_T *pStat);
+int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat);
+int birdStatAt(void *hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink);
+int birdStatAtW(void *hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink);
 int birdStatOnFd(int fd, BirdStat_T *pStat);
 int birdStatOnFdJustSize(int fd, __int64 *pcbFile);
 int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink);
diff --git a/src/lib/nt/ntstuff.h b/src/lib/nt/ntstuff.h
index f9ed594..c1a9be3 100644
--- a/src/lib/nt/ntstuff.h
+++ b/src/lib/nt/ntstuff.h
@@ -1,4 +1,4 @@
-/* $Id: ntstuff.h 2900 2016-09-09 14:42:06Z bird $ */
+/* $Id: ntstuff.h 2985 2016-11-01 18:26:35Z bird $ */
 /** @file
  * Definitions, types, prototypes and globals for NT.
  */
@@ -40,6 +40,8 @@
 #include <ntstatus.h>
 #undef timeval
 
+#include <k/kTypes.h>
+
 
 /** @defgroup grp_nt_ntstuff NT Stuff
  * @{ */
@@ -466,6 +468,14 @@ typedef struct MY_RTL_RELATIVE_NAME_U
 # define FILE_OPEN_FOR_FREE_SPACE_QUERY     0x00800000U
 #endif
 
+#ifndef DUPLICATE_CLOSE_SOURCE /* For the misnomer NtDuplicateObject. */
+# define DUPLICATE_CLOSE_SOURCE             0x00000001U
+# define DUPLICATE_SAME_ACCESS              0x00000002U
+#endif
+#ifndef DUPLICATE_SAME_ATTRIBUTES
+# define DUPLICATE_SAME_ATTRIBUTES          0x00000004U
+#endif
+
 
 /** @name NT status codes and associated macros.
  * @{ */
@@ -479,6 +489,47 @@ typedef struct MY_RTL_RELATIVE_NAME_U
 #define MY_STATUS_OBJECT_PATH_SYNTAX_BAD    ((MY_NTSTATUS)0xc000003b)
 /** @}  */
 
+/** The pseudohandle for the current process. */
+#define MY_NT_CURRENT_PROCESS               ((HANDLE)~(uintptr_t)0)
+/** The pseudohandle for the current thread. */
+#define MY_NT_CURRENT_THREAD                ((HANDLE)~(uintptr_t)1)
+
+typedef struct MY_CLIENT_ID
+{
+    HANDLE UniqueProcess;
+    HANDLE UniqueThread;
+} MY_CLIENT_ID;
+
+/** Partial TEB.   */
+typedef struct MY_PARTIAL_TEB
+{
+    NT_TIB          NtTib;
+    PVOID           EnvironmentPointer;
+    MY_CLIENT_ID    ClientId;
+    PVOID           ActiveRpcHandle;
+    PVOID           ThreadLocalStoragePointer;
+    PPEB            ProcessEnvironmentBlock;
+    KU32            LastErrorValue;
+    KU32            CountOfOwnedCriticalSections;
+    PVOID           CsrClientThread;
+    PVOID           Win32ThreadInfo;
+} MY_PARTIAL_TEB;
+
+/** Internal macro for reading uintptr_t sized TEB members. */
+#if K_ARCH == K_ARCH_AMD64
+# define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readgsqword(a_offTebMember) )
+#elif K_ARCH == K_ARCH_X86
+# define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readfsdword(a_offTebMember) )
+#else
+# else "Port me!"
+#endif
+/** Get the PEB pointer.
+ * @remark Needs stddef.h. */
+#define MY_NT_CURRENT_PEB()  ( (PPEB)MY_NT_READ_TEB_WORKER(offsetof(MY_PARTIAL_TEB, ProcessEnvironmentBlock)) )
+/** Get the TEB pointer.
+ * @remark Needs stddef.h. */
+#define MY_NT_CURRENT_TEB()  ( (PTEB)MY_NT_READ_TEB_WORKER(offsetof(NT_TIB, Self)) )
+
 
 /*******************************************************************************
 *   Global Variables                                                           *
@@ -487,6 +538,8 @@ extern MY_NTSTATUS (WINAPI * g_pfnNtClose)(HANDLE);
 extern MY_NTSTATUS (WINAPI * g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *,
                                                 PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
 extern MY_NTSTATUS (WINAPI * g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *);
+extern MY_NTSTATUS (WINAPI * g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet,
+                                                     MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions);
 extern MY_NTSTATUS (WINAPI * g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx,
                                               MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile,
                                               PULONG  puKey);
@@ -507,6 +560,9 @@ extern BOOLEAN     (WINAPI * g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const
 extern BOOLEAN     (WINAPI * g_pfnRtlEqualString)(MY_ANSI_STRING const *pAnsiStr1, MY_ANSI_STRING const *pAnsiStr2,
                                                   BOOLEAN fCaseInsensitive);
 extern UCHAR       (WINAPI * g_pfnRtlUpperChar)(UCHAR uch);
+extern ULONG       (WINAPI * g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt);
+extern VOID        (WINAPI * g_pfnRtlAcquirePebLock)(VOID);
+extern VOID        (WINAPI * g_pfnRtlReleasePebLock)(VOID);
 
 
 /** @} */
diff --git a/src/lib/nt/ntunlink.c b/src/lib/nt/ntunlink.c
index b417767..622f47e 100644
--- a/src/lib/nt/ntunlink.c
+++ b/src/lib/nt/ntunlink.c
@@ -1,4 +1,4 @@
-/* $Id: ntunlink.c 2713 2013-11-21 21:11:00Z bird $ */
+/* $Id: ntunlink.c 2997 2016-11-01 23:28:02Z bird $ */
 /** @file
  * MSC + NT unlink and variations.
  */
@@ -45,7 +45,8 @@ static MY_NTSTATUS birdMakeWritable(MY_UNICODE_STRING *pNtPath)
     MY_NTSTATUS rcNt;
     HANDLE      hFile;
 
-    rcNt = birdOpenFileUniStr(pNtPath,
+    rcNt = birdOpenFileUniStr(NULL /*hRoot*/,
+                              pNtPath,
                               FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                               FILE_ATTRIBUTE_NORMAL,
                               FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
@@ -81,12 +82,17 @@ static MY_NTSTATUS birdMakeWritable(MY_UNICODE_STRING *pNtPath)
 }
 
 
-static int birdUnlinkInternal(const char *pszFile, int fReadOnlyToo, int fFast)
+static int birdUnlinkInternal(HANDLE hRoot, const char *pszFile, int fReadOnlyToo, int fFast)
 {
     MY_UNICODE_STRING   NtPath;
     int                 rc;
 
-    rc = birdDosToNtPath(pszFile, &NtPath);
+    if (hRoot == INVALID_HANDLE_VALUE)
+        hRoot = NULL;
+    if (hRoot == NULL)
+        rc = birdDosToNtPath(pszFile, &NtPath);
+    else
+        rc = birdDosToRelativeNtPath(pszFile, &NtPath);
     if (rc == 0)
     {
         MY_NTSTATUS rcNt;
@@ -94,7 +100,7 @@ static int birdUnlinkInternal(const char *pszFile, int fReadOnlyToo, int fFast)
         {
             /* This uses FILE_DELETE_ON_CLOSE. Probably only suitable when in a hurry... */
             MY_OBJECT_ATTRIBUTES ObjAttr;
-            MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, NULL /*hRoot*/, NULL /*pSecAttr*/);
+            MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, hRoot, NULL /*pSecAttr*/);
             rcNt = g_pfnNtDeleteFile(&ObjAttr);
 
             /* In case some file system does things differently than NTFS. */
@@ -111,7 +117,8 @@ static int birdUnlinkInternal(const char *pszFile, int fReadOnlyToo, int fFast)
             int    fMayTryAgain = 1;
             for (;;)
             {
-                rcNt = birdOpenFileUniStr(&NtPath,
+                rcNt = birdOpenFileUniStr(hRoot,
+                                          &NtPath,
                                           DELETE,
                                           FILE_ATTRIBUTE_NORMAL,
                                           FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
@@ -154,18 +161,36 @@ static int birdUnlinkInternal(const char *pszFile, int fReadOnlyToo, int fFast)
 
 int birdUnlink(const char *pszFile)
 {
-    return birdUnlinkInternal(pszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/);
+    return birdUnlinkInternal(NULL /*hRoot*/, pszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/);
+}
+
+
+int birdUnlinkEx(void *hRoot, const char *pszFile)
+{
+    return birdUnlinkInternal((HANDLE)hRoot, pszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/);
 }
 
 
 int birdUnlinkForced(const char *pszFile)
 {
-    return birdUnlinkInternal(pszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/);
+    return birdUnlinkInternal(NULL /*hRoot*/, pszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/);
+}
+
+
+int birdUnlinkForcedEx(void *hRoot, const char *pszFile)
+{
+    return birdUnlinkInternal((HANDLE)hRoot, pszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/);
 }
 
 
 int birdUnlinkForcedFast(const char *pszFile)
 {
-    return birdUnlinkInternal(pszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/);
+    return birdUnlinkInternal(NULL /*hRoot*/, pszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/);
+}
+
+
+int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile)
+{
+    return birdUnlinkInternal((HANDLE)hRoot, pszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/);
 }
 
diff --git a/src/lib/nt/ntunlink.h b/src/lib/nt/ntunlink.h
index ec7d82a..195ef7f 100644
--- a/src/lib/nt/ntunlink.h
+++ b/src/lib/nt/ntunlink.h
@@ -1,4 +1,4 @@
-/* $Id: ntunlink.h 2713 2013-11-21 21:11:00Z bird $ */
+/* $Id: ntunlink.h 2997 2016-11-01 23:28:02Z bird $ */
 /** @file
  * MSC + NT unlink and variations.
  */
@@ -34,8 +34,11 @@
 #include "nttypes.h"
 
 int birdUnlink(const char *pszFile);
+int birdUnlinkEx(void *hRoot, const char *pszFile);
 int birdUnlinkForced(const char *pszFile);
+int birdUnlinkForcedEx(void *hRoot, const char *pszFile);
 int birdUnlinkForcedFast(const char *pszFile);
+int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile);
 
 #undef  unlink
 #define unlink(a_pszPath)     birdUnlinkForced(a_pszPath)
diff --git a/src/lib/nt/tstNtFts.c b/src/lib/nt/tstNtFts.c
new file mode 100644
index 0000000..d2fed4c
--- /dev/null
+++ b/src/lib/nt/tstNtFts.c
@@ -0,0 +1,244 @@
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#ifndef USE_OLD_FTS
+# include "fts-nt.h"
+#else
+# include "kmkbuiltin/ftsfake.h"
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+
+static int usage(const char *argv0)
+{
+    printf("usage: %s [options] <dirs & files>\n", argv0);
+    printf("\n"
+           "options:\n"
+           "  -d, --see-dot\n"
+           "    FTS_SEEDOT\n"
+           "  -p, --physical\n"
+           "    FTS_PHYSICAL\n"
+           "  -l, --logical\n"
+           "    FTS_LOGICAL\n"
+           "  -H, --dereference-command-line\n"
+           "    FTS_COMFOLLOW\n"
+           "  -L, --dereference\n"
+           "    Follow symbolic links while scanning directories.\n"
+           "  -P, --no-dereference\n"
+           "    Do not follow symbolic links while scanning directories.\n"
+           "  -c, --no-chdir\n"
+           "    FTS_NOCHDIR\n"
+           "  -s, --no-stat\n"
+           "    FTS_NOSTAT\n"
+           "  -x, --one-file-system\n"
+           "    FTS_XDEV\n"
+           "  -q, --quiet\n"
+           "    Quiet operation, no output.\n"
+           "  -v, --verbose\n"
+           "    Verbose operation (default).\n"
+           );
+    return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+    FTS        *pFts;
+    int         i;
+    int         rcExit       = 0;
+    int         cVerbosity   = 1;
+    int         fFollowLinks = 0;
+    int         fFtsFlags    = 0;
+    unsigned    fDoneOptions = 0;
+    unsigned    cFtsArgs     = 0;
+    char const **papszFtsArgs = calloc(argc + 1, sizeof(char *));
+
+    /*
+     * Parse options and heap up non-options.
+     */
+    for (i = 1; i < argc; i++)
+    {
+        const char *pszArg = argv[i];
+        if (*pszArg == '-' && !fDoneOptions)
+        {
+            char chOpt = *++pszArg;
+            pszArg++;
+            if (chOpt == '-')
+            {
+                chOpt = *pszArg++;
+                if (!chOpt)
+                {
+                    fDoneOptions = 1;
+                    continue;
+                }
+                if (strcmp(pszArg, "help") == 0)
+                    chOpt = 'h';
+                else if (strcmp(pszArg, "version") == 0)
+                    chOpt = 'V';
+                else if (strcmp(pszArg, "see-dot") == 0)
+                    chOpt = 'd';
+                else if (strcmp(pszArg, "physical") == 0)
+                    chOpt = 'p';
+                else if (strcmp(pszArg, "logical") == 0)
+                    chOpt = 'l';
+                else if (strcmp(pszArg, "dereference-command-line") == 0)
+                    chOpt = 'H';
+                else if (strcmp(pszArg, "no-chdir") == 0)
+                    chOpt = 'c';
+                else if (strcmp(pszArg, "no-stat") == 0)
+                    chOpt = 's';
+                else if (strcmp(pszArg, "one-file-system") == 0)
+                    chOpt = 'x';
+                else if (strcmp(pszArg, "quiet") == 0)
+                    chOpt = 'q';
+                else if (strcmp(pszArg, "verbose") == 0)
+                    chOpt = 'v';
+                else
+                {
+                    fprintf(stderr, "syntax error: Unknown option: --%s\n", pszArg);
+                    return 2;
+                }
+                pszArg = "";
+            }
+            do
+            {
+                switch (chOpt)
+                {
+                    case '?':
+                    case 'h':
+                        return usage(argv[0]);
+                    case 'V':
+                        printf("v0.0.0\n");
+                        return 0;
+
+                    case 'd':
+                        fFtsFlags |= FTS_SEEDOT;
+                        break;
+                    case 'l':
+                        fFtsFlags |= FTS_LOGICAL;
+                        break;
+                    case 'p':
+                        fFtsFlags |= FTS_PHYSICAL;
+                        break;
+                    case 'H':
+                        fFtsFlags |= FTS_COMFOLLOW;
+                        break;
+                    case 'c':
+                        fFtsFlags |= FTS_NOCHDIR;
+                        break;
+                    case 's':
+                        fFtsFlags |= FTS_NOSTAT;
+                        break;
+                    case 'x':
+                        fFtsFlags |= FTS_XDEV;
+                        break;
+                    case 'L':
+                        fFollowLinks = 1;
+                        break;
+                    case 'P':
+                        fFollowLinks = 0;
+                        break;
+
+                    case 'q':
+                        cVerbosity = 0;
+                        break;
+                    case 'v':
+                        cVerbosity++;
+                        break;
+
+                    default:
+                        fprintf(stderr, "syntax error: Unknown option: -%c (%s)\n", chOpt, argv[i]);
+                        return 2;
+                }
+                chOpt = *pszArg++;
+            } while (chOpt != '\0');
+        }
+        else
+            papszFtsArgs[cFtsArgs++] = pszArg;
+    }
+
+#ifdef USE_OLD_FTS
+    if (papszFtsArgs[0] == NULL)
+    {
+        fprintf(stderr, "Nothing to do\n");
+        return 1;
+    }
+#endif
+
+    /*
+     * Do the traversal.
+     */
+    errno = 0;
+    pFts = fts_open((char **)papszFtsArgs, fFtsFlags, NULL /*pfnCompare*/);
+    if (pFts)
+    {
+        for (;;)
+        {
+            FTSENT *pFtsEnt = fts_read(pFts);
+            if (pFtsEnt)
+            {
+                const char *pszState;
+                switch (pFtsEnt->fts_info)
+                {
+                    case FTS_D:         pszState = "D"; break;
+                    case FTS_DC:        pszState = "DC"; break;
+                    case FTS_DEFAULT:   pszState = "DEFAULT"; break;
+                    case FTS_DNR:       pszState = "DNR"; break;
+                    case FTS_DOT:       pszState = "DOT"; break;
+                    case FTS_DP:        pszState = "DP"; break;
+                    case FTS_ERR:       pszState = "ERR"; break;
+                    case FTS_F:         pszState = "F"; break;
+                    case FTS_INIT:      pszState = "INIT"; break;
+                    case FTS_NS:        pszState = "NS"; break;
+                    case FTS_NSOK:      pszState = "NSOK"; break;
+                    case FTS_SL:        pszState = "SL"; break;
+                    case FTS_SLNONE:    pszState = "SLNONE"; break;
+                    default:
+                        pszState = "Invalid";
+                        rcExit = 1;
+                        break;
+                }
+
+                if (cVerbosity > 0)
+                    printf("%8s %s\n", pszState, pFtsEnt->fts_accpath);
+                if (   pFtsEnt->fts_info == FTS_SL
+                    && pFtsEnt->fts_number == 0
+                    && fFollowLinks
+                    && (   (fFtsFlags & FTS_COMFOLLOW)
+                        || pFtsEnt->fts_level > FTS_ROOTLEVEL) ) {
+                    pFtsEnt->fts_number++;
+                    fts_set(pFts, pFtsEnt, FTS_FOLLOW);
+                }
+            }
+            else
+            {
+                if (errno != 0)
+                {
+                    fprintf(stderr, "fts_read failed: errno=%d\n", errno);
+                    rcExit = 1;
+                }
+                break;
+            }
+        } /* enum loop */
+
+        errno = 0;
+        i = fts_close(pFts);
+        if (i != 0)
+        {
+            fprintf(stderr, "fts_close failed: errno=%d\n", errno);
+            rcExit = 1;
+        }
+    }
+    else
+    {
+        fprintf(stderr, "fts_open failed: errno=%d (cFtsArgs=%u)\n", errno, cFtsArgs);
+        rcExit = 1;
+    }
+
+    return rcExit;
+}
diff --git a/src/lib/quote_argv.c b/src/lib/quote_argv.c
index 016f945..243c48f 100644
--- a/src/lib/quote_argv.c
+++ b/src/lib/quote_argv.c
@@ -1,4 +1,4 @@
-/* $Id: quote_argv.c 2894 2016-09-08 13:27:56Z bird $ */
+/* $Id: quote_argv.c 2912 2016-09-14 13:36:15Z bird $ */
 /** @file
  * quote_argv - Correctly quote argv for spawn, windows specific.
  */
@@ -79,6 +79,7 @@ static int isWatcomPassThruOption(const char *pszArg)
  * For details on how MSC parses the command line, see "Parsing C Command-Line
  * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
  *
+ * @returns 0 on success, -1 if out of memory.
  * @param   argc                The argument count.
  * @param   argv                The argument vector.
  * @param   fWatcomBrainDamage  Set if we're catering for wcc, wcc386 or similar
@@ -89,7 +90,7 @@ static int isWatcomPassThruOption(const char *pszArg)
  *                              depends on which argv you're working on.
  *                              Suggest doing the latter if it's main()'s argv.
  */
-void quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
+int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
 {
     int i;
     for (i = 0; i < argc; i++)
@@ -121,6 +122,8 @@ void quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
             int    fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\');
             size_t cchNew       = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2;
             char  *pszNew       = (char *)malloc(cchNew + 1 /*term*/ + 3 /*passthru hack*/);
+            if (!pszNew)
+                return -1;
 
             argv[i] = pszNew;
 
@@ -207,5 +210,6 @@ void quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
     }
 
     /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/
+    return 0;
 }
 
diff --git a/src/lib/quote_argv.h b/src/lib/quote_argv.h
index 3f6b42e..6e0a13e 100644
--- a/src/lib/quote_argv.h
+++ b/src/lib/quote_argv.h
@@ -1,4 +1,4 @@
-/* $Id: quote_argv.h 2851 2016-08-31 17:30:52Z bird $ */
+/* $Id: quote_argv.h 2912 2016-09-14 13:36:15Z bird $ */
 /** @file
  * quote_argv - Correctly quote argv for spawn, windows specific.
  */
@@ -33,7 +33,7 @@
 #define ___quote_argv_h___
 
 #include "mytypes.h"
-extern void quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak);
+extern int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak);
 
 #endif
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/kbuild.git



More information about the Pkg-virtualbox-commits mailing list