Codebase list kbuild / c1266c4
Imported Upstream version 0.1.9998svn2997+dfsg Gianfranco Costamagna 7 years ago
56 changed file(s) with 8918 addition(s) and 2261 deletion(s). Raw diff Collapse all Expand all
0 # $Id: footer-pass2-compiling-targets.kmk 2795 2015-09-15 23:35:37Z bird $
0 # $Id: footer-pass2-compiling-targets.kmk 2952 2016-09-21 18:52:08Z bird $
11 ## @file
22 # kBuild - Footer - Target lists - Pass 2 - Compiling Targets.
33 #
8282 $$$$($(target)_INTERMEDIATES.$(bld_trg_cpu)) \
8383 $$$$($(target)_INTERMEDIATES.$(bld_type))
8484 %$$(call MSG_COMPILE,$(target),$(source),$$@,$(type))
85 ifdef TOOL_$(tool)_COMPILE_$(type)_DONT_PURGE_OUTPUT
85 ifndef TOOL_$(tool)_COMPILE_$(type)_DONT_PURGE_OUTPUT
8686 $$(QUIET)$$(RM) -f -- $(dep) $(obj) $($(target)_$(source)_OUTPUT_) $($(target)_OUTPUT_MAYBE_)
8787 endif
8888 endif
489489 $($(target)_USES.$(bld_type))\
490490 $($(target)_USES)
491491 $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre))
492 $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre_2))
492493
493494 # source -> object
494495 $(evalval def_target_sources)
693694 $($(target)_USES.$(bld_type))\
694695 $($(target)_USES)
695696 $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre))
697 $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre_2))
696698
697699 # source -> object
698700 $(evalval def_target_sources)
0 # $Id: footer-pass2-fetches.kmk 2726 2014-02-26 23:23:54Z bird $
0 # $Id: footer-pass2-fetches.kmk 2912 2016-09-14 13:36:15Z bird $
11 ## @file
22 # kBuild - Footer - Target lists - Pass 2 - Fetches.
33 #
360360 %$$(if $$(_TARGET_$(target)_DIGEST),$$(if $$(eq $$(file-size $(out).lst),-1)\
361361 ,$$(call MSG_REFETCH,$(target)),$$(call MSG_FETCH,$(target))),$$(call MSG_UNFETCH,$(target)))
362362 $$(QUIET)$(TEST_EXT) -f $(out).lst -- $$(MAKE) -f $(MAKEFILE) --no-print-directory $(out)_unfetched
363 if $(KBUILD_KMK_REVISION) > 2911
364 $$(QUIET)kmk_builtin_dircache deleted "$(dir $(out))"
365 endif
363366 $$(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 $$@))
364367 $$(QUIET2)$$(if $$(_TARGET_$(target)_DIGEST),$$(APPEND) $$@ "_TARGET_$(target)_DIGEST_PREV := $(_TARGET_$(target)_DIGEST)")
365368
0 # $Id: header.kmk 2895 2016-09-08 13:28:37Z bird $
0 # $Id: header.kmk 2971 2016-09-27 11:25:09Z bird $
11 ## @file
22 # kBuild - File included at top of a makefile.
33 #
7878 # The revision in which this file was last modified.
7979 # This can be useful when using development versions of kBuild.
8080 #
81 KMK_REVISION := $(patsubst %:,, $Rev: 2895 $ )
81 KMK_REVISION := $(patsubst %:,, $Rev: 2971 $ )
8282
8383
8484 #
191191 KBUILD_ARCHES := x86 amd64 sparc32 sparc64 s390 s390x ppc32 ppc64 mips32 mips64 ia64 hppa32 hppa64 arm alpha noarch
192192 KBUILD_ARCHES_64 := amd64 sparc64 s390x ppc64 mips64 ia64 hppa64 alpha
193193 KBUILD_ARCHES_32 := x86 sparc32 s390 ppc32 mips32 hppa32 arm
194
195
196 #
197 # Mapping of kBuild OS + ARCH to GNU system type wildcards.
198 # For use with the foreach/append/prepend and wildcard functions.
199 #
200 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.darwin.x86 = i?86-apple-darwin*
201 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.darwin.amd64 = x86_64-apple-darwin* amd64-apple-darwin*
202 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.freebsd.x86 = i?86-*freebsd*
203 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.freebsd.amd64 = x86_64-*freebsd* amd64-*freebsd*
204 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.linux.x86 = i?86-*linux-gnu
205 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.linux.amd64 = x86_64-*linux-gnu amd64-*linux-gnu
206 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.netbsd.x86 = i?86-*netbsd*
207 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.netbsd.amd64 = x86_64-*netbsd* amd64-*netbsd*
208 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.os2.x86 = i?86-*os2*
209 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.x86 = i?86-*solaris2*
210 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.amd64 = amd64-*solaris2* x86_64-*solaris2*
211 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.sparc32 = sparc-*solaris2*
212 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.sparc64 = sparc64-*solaris2* sparcv9-*solaris2*
213 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.win.x86 = i?86-*mingw32* i?86-*msys* i?86-*cygwin*
214 KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.win.amd64 = x86_64-*mingw64* amd64-*mingw64* x86_64-*msys* amd64-*msys* x86_64-*cygwin* amd64-*cygwin*
194215
195216
196217 #
367388 $(error kBuild: The KBUILD_TARGET_CPU value '$(KBUILD_TARGET_CPU)' is the same as the KBUILD_TYPE!)
368389 endif
369390 endif
391
392 # Short hand for $(KBUILD_TARGET).$(KBUILD_TARGET_ARCH).
393 KBUILD_TARGET_DOT_ARCH = $(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)
394 KBUILD_HOST_DOT_ARCH = $(KBUILD_HOST).$(KBUILD_TARGET_ARCH)
370395
371396
372397 #
700725 PRINTF := $(PRINTF_INT)
701726
702727 REDIRECT_EXT:= $(KBUILD_BIN_PATH)/kmk_redirect$(HOSTSUFF_EXE)
728 if $(KBUILD_KMK_REVISION) > 2911
729 REDIRECT_INT:= kmk_builtin_redirect
730 else
703731 REDIRECT_INT:= $(REDIRECT_EXT)
732 endif
704733 REDIRECT := $(REDIRECT_INT)
705734
706735 RM_EXT := $(KBUILD_BIN_PATH)/kmk_rm$(HOSTSUFF_EXE)
0 # $Id: NASM.kmk 2890 2016-09-07 23:39:29Z bird $
0 # $Id: NASM.kmk 2929 2016-09-16 21:19:14Z bird $
11 ## @file
22 # kBuild Tool Config - Netwide Assembler v0.98+.
33 #
8585 -MD "$(dep)" -MP\
8686 $(abspath $(source))
8787 else
88 $(QUIET)$(REDIRECT) -C $(PATH_OUT_BASE) $(TOOL_NASM_AS)\
88 $(QUIET)$(REDIRECT) -C $(PATH_OUT_BASE) -- $(TOOL_NASM_AS)\
8989 $(flags) $(addsuffix /,$(addprefix -i, $(incs))) $(addprefix -D, $(defs))\
9090 -l $(outbase).lst\
9191 -o $(obj)\
0 # $Id: VCC100.kmk 2795 2015-09-15 23:35:37Z bird $
0 # $Id: VCC100.kmk 2964 2016-09-23 11:08:04Z bird $
11 ## @file
22 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting $(KBUILD_TARGET).
33 #
106106 # @param $(2) The extension.
107107 TOOL_VCC100_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2)
108108
109
110 # General Properties used by kBuild
109111 TOOL_VCC100_COBJSUFF ?= .obj
110 TOOL_VCC100_CFLAGS ?= -TC -nologo
111 TOOL_VCC100_CFLAGS.debug ?= -Zi
112 TOOL_VCC100_CFLAGS.dbgopt ?= -O2 -Zi
112 TOOL_VCC100_CFLAGS ?= -TC -nologo -Zi
113 TOOL_VCC100_CFLAGS.debug ?=
114 TOOL_VCC100_CFLAGS.dbgopt ?= -O2
113115 TOOL_VCC100_CFLAGS.release ?= -O2
114116 TOOL_VCC100_CFLAGS.profile ?= -O2
115117 TOOL_VCC100_CINCS ?= $(PATH_TOOL_VCC100_INC)
116118 TOOL_VCC100_CDEFS ?=
117119
118120 TOOL_VCC100_CXXOBJSUFF ?= .obj
119 TOOL_VCC100_CXXFLAGS ?= -TP -nologo
120 TOOL_VCC100_CXXFLAGS.debug ?= -Zi
121 TOOL_VCC100_CXXFLAGS.dbgopt ?= -O2 -Zi
121 TOOL_VCC100_CXXFLAGS ?= -TP -nologo -Zi
122 TOOL_VCC100_CXXFLAGS.debug ?=
123 TOOL_VCC100_CXXFLAGS.dbgopt ?= -O2
122124 TOOL_VCC100_CXXFLAGS.release ?= -O2
123125 TOOL_VCC100_CXXFLAGS.profile ?= -O2
124126 TOOL_VCC100_CXXINCS ?= $(PATH_TOOL_VCC100_INC) $(PATH_TOOL_VCC100_ATLMFC_INC)
161163 # @param $(objsuff) Object suffix.
162164 TOOL_VCC100_COMPILE_C_DEPEND =
163165 TOOL_VCC100_COMPILE_C_DEPORD =
164 ifdef KBUILD_USE_KOBJCACHE
165 TOOL_VCC100_COMPILE_C_USES_KOBJCACHE = 1
166 TOOL_VCC100_COMPILE_C_OUTPUT = $(outbase).i
167 TOOL_VCC100_COMPILE_C_OUTPUT_MAYBE =
168 define TOOL_VCC100_COMPILE_C_CMDS
169 $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
170 --make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
171 --kObjCache-cpp $(outbase).i\
172 $(TOOL_VCC100_CC) -E\
173 $(subst -Zi,-Z7,$(flags))\
174 $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
175 $(subst /,\\,$(abspath $(source))) \
176 --kObjCache-cc $(obj)\
177 $(TOOL_VCC100_CC) -c\
178 $(subst -Zi,-Z7,$(flags))\
179 -Fo$(obj)\
180 $(outbase).i
181 endef
182 else # !KBUILD_USE_KOBJCACHE
183 TOOL_VCC100_COMPILE_C_OUTPUT = $(call TOOL_VCC100_PDB, $(outbase)-obj,idb)
184 TOOL_VCC100_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100_PDB, $(outbase)-obj,pdb)
166 TOOL_VCC100_COMPILE_C_OUTPUT =
167 TOOL_VCC100_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100_PDB, $(outbase)-obj,idb)
185168 define TOOL_VCC100_COMPILE_C_CMDS
186169 $(QUIET)$(TOOL_VCC100_CC) -c\
187170 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
188171 -Fd$(outbase)-obj.pdb \
189 -FD\
190172 -Fo$(obj)\
191173 $(subst /,\\,$(abspath $(source)))
192 $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100_PDB,$(outbase)-obj,idb)
193 endef
194 endif # !KBUILD_USE_KOBJCACHE
174 $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
175 endef
195176
196177
197178 ## Compile C++ source.
207188 #
208189 # @param $(outbase) Output basename (full). Use this for list files and such.
209190 # @param $(objsuff) Object suffix.
210 TOOL_VCC100_COMPILE_CXX_DEPEND =
191 TOOL_VCC100_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE)
211192 TOOL_VCC100_COMPILE_CXX_DEPORD =
212 ifdef KBUILD_USE_KOBJCACHE
213 TOOL_VCC100_COMPILE_CXX_USES_KOBJCACHE = 1
214 TOOL_VCC100_COMPILE_CXX_OUTPUT = $(outbase).ii
215 TOOL_VCC100_COMPILE_CXX_OUTPUT_MAYBE =
216 define TOOL_VCC100_COMPILE_CXX_CMDS
217 $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
218 --make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
219 --kObjCache-cpp $(outbase).ii\
220 $(TOOL_VCC100_CXX) -E\
221 $(subst -Zi,-Z7,$(flags))\
222 $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
223 $(subst /,\\,$(abspath $(source))) \
224 --kObjCache-cc $(obj)\
225 $(TOOL_VCC100_CXX) -c\
226 $(subst -Zi,-Z7,$(flags))\
227 -Fo$(obj)\
228 $(outbase).ii
229 endef
230 else # !KBUILD_USE_KOBJCACHE
231 TOOL_VCC100_COMPILE_CXX_OUTPUT = $(call TOOL_VCC100_PDB, $(outbase)-obj,idb)
232 TOOL_VCC100_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC100_PDB, $(outbase)-obj,pdb)
193 TOOL_VCC100_COMPILE_CXX_OUTPUT =
194 TOOL_VCC100_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\
195 ,,$(call TOOL_VCC100_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100_PDB, $(outbase)-obj,idb))
233196 define TOOL_VCC100_COMPILE_CXX_CMDS
234197 $(QUIET)$(TOOL_VCC100_CXX) -c\
235198 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
236 -Fd$(outbase)-obj.pdb \
237 -FD\
199 $(if-expr defined($(target)_PCH_HDR)\
200 ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
201 -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
238202 -Fo$(obj)\
239203 $(subst /,\\,$(abspath $(source)))
240 $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100_PDB,$(outbase)-obj,idb)
241 endef
242 endif # !KBUILD_USE_KOBJCACHE
204 $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
205 endef
206
207
208 #
209 # Helper tool for creating the precompiled C++ header.
210 #
211 # It only have the C++ compile bits and it's purpose is to skip bits
212 # related _1_VCC_PCH_FILE and add -Yc.
213 #
214 TOOL_VCC100-PCH := Helper for creating precompiled header using CXX handling.
215 TOOL_VCC100-PCH_EXTENDS := VCC100
216 TOOL_VCC100-PCH_CXXOBJSUFF := .obj
217 TOOL_VCC100-PCH_CXXINCS = $(TOOL_VCC100_CXXINCS)
218 TOOL_VCC100-PCH_CXXFLAGS.debug = $(TOOL_VCC100_CXXFLAGS.debug)
219 TOOL_VCC100-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC100_CXXFLAGS.dbgopt)
220 TOOL_VCC100-PCH_CXXFLAGS.release = $(TOOL_VCC100_CXXFLAGS.release)
221 TOOL_VCC100-PCH_CXXFLAGS.profile = $(TOOL_VCC100_CXXFLAGS.profile)
222 TOOL_VCC100-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE)
223 TOOL_VCC100-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE)
224 TOOL_VCC100-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
225 TOOL_VCC100-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE)
226 ifdef TOOL_VCC100_KSUBMIT
227 define TOOL_VCC100-PCH_COMPILE_CXX_CMDS
228 $(QUIET)$(TOOL_VCC100_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
229 -- $(TOOL_VCC100_CXX) -c -Yc\
230 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
231 -Fp$($(target)_1_VCC_PCH_FILE) \
232 -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
233 -Fo$(obj)\
234 -TP \
235 $(subst /,\\,$(abspath $(source)))
236 endef
237 else
238 define TOOL_VCC100-PCH_COMPILE_CXX_CMDS
239 $(QUIET)$(TOOL_VCC100_CXX) -c -Yc\
240 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
241 -Fp$($(target)_1_VCC_PCH_FILE) \
242 -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
243 -Fo$(obj)\
244 -TP \
245 $(subst /,\\,$(abspath $(source)))
246 $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)
247
248 endef
249 endif # !TOOL_VCC100_KSUBMIT
250
243251
244252 ## @todo configure the assembler template.
245253
290298 ,\"$(arg)\")
291299 $(QUIET)$(TOOL_VCC100_AR) $(flags) /OUT:$(out) @$(outbase).rsp
292300 endef
293
294
295301
296302
297303 ## Link program
0 # $Id: VCC100AMD64.kmk 2902 2016-09-09 17:15:22Z bird $
0 # $Id: VCC100AMD64.kmk 2964 2016-09-23 11:08:04Z bird $
11 ## @file
22 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting AMD64.
33 #
7878 ifeq ($(KBUILD_HOST),win)
7979 ifneq ($(substr $(PATH_TOOL_VCC100AMD64_BIN),-9),x86_amd64)
8080 TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --64-bit
81 TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
8182 else
82 TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --32-bit
83 # "fatal error C1902: Program database manager mismatch; please check your installation" when mixing with the 32-bit compiler.
84 #TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --32-bit
85 #TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
8386 endif
84 TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
8587 endif
8688 endif
8789
102104 # @param $(2) The extension.
103105 TOOL_VCC100AMD64_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2)
104106
107
108 # General Properties used by kBuild
105109 TOOL_VCC100AMD64_COBJSUFF ?= .obj
106 TOOL_VCC100AMD64_CFLAGS ?= -TC -nologo
107 TOOL_VCC100AMD64_CFLAGS.debug ?= -Zi
108 TOOL_VCC100AMD64_CFLAGS.dbgopt ?= -O2 -Zi
110 TOOL_VCC100AMD64_CFLAGS ?= -TC -nologo -Zi
111 TOOL_VCC100AMD64_CFLAGS.debug ?=
112 TOOL_VCC100AMD64_CFLAGS.dbgopt ?= -O2
109113 TOOL_VCC100AMD64_CFLAGS.release ?= -O2
110114 TOOL_VCC100AMD64_CFLAGS.profile ?= -O2
111115 TOOL_VCC100AMD64_CINCS ?= $(PATH_TOOL_VCC100AMD64_INC)
112116 TOOL_VCC100AMD64_CDEFS ?=
113117
114118 TOOL_VCC100AMD64_CXXOBJSUFF ?= .obj
115 TOOL_VCC100AMD64_CXXFLAGS ?= -TP -nologo
116 TOOL_VCC100AMD64_CXXFLAGS.debug ?= -Zi
117 TOOL_VCC100AMD64_CXXFLAGS.dbgopt ?= -O2 -Zi
119 TOOL_VCC100AMD64_CXXFLAGS ?= -TP -nologo -Zi
120 TOOL_VCC100AMD64_CXXFLAGS.debug ?=
121 TOOL_VCC100AMD64_CXXFLAGS.dbgopt ?= -O2
118122 TOOL_VCC100AMD64_CXXFLAGS.release ?= -O2
119123 TOOL_VCC100AMD64_CXXFLAGS.profile ?= -O2
120124 TOOL_VCC100AMD64_CXXINCS ?= $(PATH_TOOL_VCC100AMD64_INC) $(PATH_TOOL_VCC100AMD64_ATLMFC_INC)
151155 # @param $(objsuff) Object suffix.
152156 TOOL_VCC100AMD64_COMPILE_C_DEPEND =
153157 TOOL_VCC100AMD64_COMPILE_C_DEPORD =
154 ifdef KBUILD_USE_KOBJCACHE
155 TOOL_VCC100AMD64_COMPILE_C_USES_KOBJCACHE = 1
156 TOOL_VCC100AMD64_COMPILE_C_OUTPUT = $(outbase).i
157 TOOL_VCC100AMD64_COMPILE_C_OUTPUT_MAYBE =
158 define TOOL_VCC100AMD64_COMPILE_C_CMDS
159 $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
160 --make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
161 --kObjCache-cpp $(outbase).i\
162 $(TOOL_VCC100AMD64_CC) -E\
163 $(subst -Zi,-Z7,$(flags))\
164 $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
165 $(subst /,\\,$(abspath $(source))) \
166 --kObjCache-cc $(obj)\
167 $(TOOL_VCC100AMD64_CC) -c\
168 $(subst -Zi,-Z7,$(flags))\
169 -Fo$(obj)\
170 $(outbase).i
171 endef
172 else # !KBUILD_USE_KOBJCACHE
173 TOOL_VCC100AMD64_COMPILE_C_OUTPUT = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb)
174 TOOL_VCC100AMD64_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb)
175 ifdef TOOL_VCC100AMD64_KSUBMIT
176 define TOOL_VCC100AMD64_COMPILE_C_CMDS
158 TOOL_VCC100AMD64_COMPILE_C_OUTPUT =
159 TOOL_VCC100AMD64_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb)
160 ifdef TOOL_VCC100AMD64_KSUBMIT
161 TOOL_VCC100AMD64_COMPILE_C_DONT_PURGE_OUTPUT := 1 # speed
162 define TOOL_VCC100AMD64_COMPILE_C_CMDS
177163 $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
178164 -- $(TOOL_VCC100AMD64_CC) -c\
179165 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
180166 -Fd$(outbase)-obj.pdb \
181 -FD\
182 -Fo$(obj)\
183 $(subst /,\\,$(abspath $(source)))
184 endef
185 else
186 define TOOL_VCC100AMD64_COMPILE_C_CMDS
167 -Fo$(obj)\
168 $(subst /,\\,$(abspath $(source)))
169 endef
170 else
171 define TOOL_VCC100AMD64_COMPILE_C_CMDS
187172 $(QUIET)$(TOOL_VCC100AMD64_CC) -c\
188173 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
189174 -Fd$(outbase)-obj.pdb \
190 -FD\
191 -Fo$(obj)\
192 $(subst /,\\,$(abspath $(source)))
193 $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100AMD64_PDB,$(outbase)-obj,idb)
194 endef
195 endif # !TOOL_VCC100AMD64_KSUBMIT
196 endif # !KBUILD_USE_KOBJCACHE
175 -Fo$(obj)\
176 $(subst /,\\,$(abspath $(source)))
177 $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
178 endef
179 endif # !TOOL_VCC100AMD64_KSUBMIT
197180
198181
199182 ## Compile C++ source.
209192 #
210193 # @param $(outbase) Output basename (full). Use this for list files and such.
211194 # @param $(objsuff) Object suffix.
212 TOOL_VCC100AMD64_COMPILE_CXX_DEPEND =
195 TOOL_VCC100AMD64_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE)
213196 TOOL_VCC100AMD64_COMPILE_CXX_DEPORD =
214 ifdef KBUILD_USE_KOBJCACHE
215 TOOL_VCC100AMD64_COMPILE_CXX_USES_KOBJCACHE = 1
216 TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT = $(outbase).ii
217 TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT_MAYBE =
218 define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
219 $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
220 --make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
221 --kObjCache-cpp $(outbase).ii\
222 $(TOOL_VCC100AMD64_CXX) -E\
223 $(subst -Zi,-Z7,$(flags))\
224 $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
225 $(subst /,\\,$(abspath $(source))) \
226 --kObjCache-cc $(obj)\
227 $(TOOL_VCC100AMD64_CXX) -c\
228 $(subst -Zi,-Z7,$(flags))\
229 -Fo$(obj)\
230 $(outbase).ii
231 endef
232 else # !KBUILD_USE_KOBJCACHE
233 TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb)
234 TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb)
235 ifdef TOOL_VCC100AMD64_KSUBMIT
236 define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
197 TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT =
198 TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\
199 ,,$(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb))
200 ifdef TOOL_VCC100AMD64_KSUBMIT
201 TOOL_VCC100AMD64_COMPILE_CXX_DONT_PURGE_OUTPUT := 1 # speed
202 define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
237203 $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
238204 -- $(TOOL_VCC100AMD64_CXX) -c\
239205 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
240 -Fd$(outbase)-obj.pdb \
241 -FD\
242 -Fo$(obj)\
243 $(subst /,\\,$(abspath $(source)))
244 endef
245 else
246 define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
206 $(if-expr defined($(target)_PCH_HDR)\
207 ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
208 -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
209 -Fo$(obj)\
210 $(subst /,\\,$(abspath $(source)))
211 endef
212 else
213 define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
247214 $(QUIET)$(TOOL_VCC100AMD64_CXX) -c\
248215 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
249 -Fd$(outbase)-obj.pdb \
250 -FD\
251 -Fo$(obj)\
252 $(subst /,\\,$(abspath $(source)))
253 $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100AMD64_PDB,$(outbase)-obj,idb)
254 endef
255 endif # !TOOL_VCC100AMD64_KSUBMIT
256 endif # !KBUILD_USE_KOBJCACHE
216 $(if-expr defined($(target)_PCH_HDR)\
217 ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
218 -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
219 -Fo$(obj)\
220 $(subst /,\\,$(abspath $(source)))
221 $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
222 endef
223 endif # !TOOL_VCC100AMD64_KSUBMIT
224
225
226 #
227 # Helper tool for creating the precompiled C++ header.
228 #
229 # It only have the C++ compile bits and it's purpose is to skip bits
230 # related _1_VCC_PCH_FILE and add -Yc.
231 #
232 TOOL_VCC100AMD64-PCH := Helper for creating precompiled header using CXX handling.
233 TOOL_VCC100AMD64-PCH_EXTENDS := VCC100AMD64
234 TOOL_VCC100AMD64-PCH_CXXOBJSUFF := .obj
235 TOOL_VCC100AMD64-PCH_CXXINCS = $(TOOL_VCC100AMD64_CXXINCS)
236 TOOL_VCC100AMD64-PCH_CXXFLAGS.debug = $(TOOL_VCC100AMD64_CXXFLAGS.debug)
237 TOOL_VCC100AMD64-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC100AMD64_CXXFLAGS.dbgopt)
238 TOOL_VCC100AMD64-PCH_CXXFLAGS.release = $(TOOL_VCC100AMD64_CXXFLAGS.release)
239 TOOL_VCC100AMD64-PCH_CXXFLAGS.profile = $(TOOL_VCC100AMD64_CXXFLAGS.profile)
240 TOOL_VCC100AMD64-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE)
241 TOOL_VCC100AMD64-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE)
242 TOOL_VCC100AMD64-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
243 TOOL_VCC100AMD64-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE)
244 ifdef TOOL_VCC100AMD64_KSUBMIT
245 define TOOL_VCC100AMD64-PCH_COMPILE_CXX_CMDS
246 $(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
247 $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
248 -- $(TOOL_VCC100AMD64_CXX) -c -Yc\
249 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
250 -Fp$($(target)_1_VCC_PCH_FILE) \
251 -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
252 -Fo$(obj)\
253 -TP \
254 $(subst /,\\,$(abspath $(source)))
255 endef
256 else
257 define TOOL_VCC100AMD64-PCH_COMPILE_CXX_CMDS
258 $(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
259 $(QUIET)$(TOOL_VCC100AMD64_CXX) -c -Yc\
260 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
261 -Fp$($(target)_1_VCC_PCH_FILE) \
262 -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
263 -Fo$(obj)\
264 -TP \
265 $(subst /,\\,$(abspath $(source)))
266 $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)
267
268 endef
269 endif # !TOOL_VCC100AMD64_KSUBMIT
270
257271
258272 ## @todo configure the assembler template.
259273
0 # $Id: VCC100X86.kmk 2902 2016-09-09 17:15:22Z bird $
0 # $Id: VCC100X86.kmk 2964 2016-09-23 11:08:04Z bird $
11 ## @file
22 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting x86.
33 #
100100
101101 # General Properties used by kBuild
102102 TOOL_VCC100X86_COBJSUFF ?= .obj
103 TOOL_VCC100X86_CFLAGS ?= -TC -nologo
104 TOOL_VCC100X86_CFLAGS.debug ?= -Zi
105 TOOL_VCC100X86_CFLAGS.dbgopt ?= -O2 -Zi
103 TOOL_VCC100X86_CFLAGS ?= -TC -nologo -Zi
104 TOOL_VCC100X86_CFLAGS.debug ?=
105 TOOL_VCC100X86_CFLAGS.dbgopt ?= -O2
106106 TOOL_VCC100X86_CFLAGS.release ?= -O2
107107 TOOL_VCC100X86_CFLAGS.profile ?= -O2
108108 TOOL_VCC100X86_CINCS ?= $(PATH_TOOL_VCC100X86_INC)
109109 TOOL_VCC100X86_CDEFS ?=
110110
111111 TOOL_VCC100X86_CXXOBJSUFF ?= .obj
112 TOOL_VCC100X86_CXXFLAGS ?= -TP -nologo
113 TOOL_VCC100X86_CXXFLAGS.debug ?= -Zi
114 TOOL_VCC100X86_CXXFLAGS.dbgopt ?= -O2 -Zi
112 TOOL_VCC100X86_CXXFLAGS ?= -TP -nologo -Zi
113 TOOL_VCC100X86_CXXFLAGS.debug ?=
114 TOOL_VCC100X86_CXXFLAGS.dbgopt ?= -O2
115115 TOOL_VCC100X86_CXXFLAGS.release ?= -O2
116116 TOOL_VCC100X86_CXXFLAGS.profile ?= -O2
117117 TOOL_VCC100X86_CXXINCS ?= $(PATH_TOOL_VCC100X86_INC) $(PATH_TOOL_VCC100X86_ATLMFC_INC)
148148 # @param $(objsuff) Object suffix.
149149 TOOL_VCC100X86_COMPILE_C_DEPEND =
150150 TOOL_VCC100X86_COMPILE_C_DEPORD =
151 ifdef KBUILD_USE_KOBJCACHE
152 TOOL_VCC100X86_COMPILE_C_USES_KOBJCACHE = 1
153 TOOL_VCC100X86_COMPILE_C_OUTPUT = $(outbase).i
154 TOOL_VCC100X86_COMPILE_C_OUTPUT_MAYBE =
155 define TOOL_VCC100X86_COMPILE_C_CMDS
156 $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
157 --make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
158 --kObjCache-cpp $(outbase).i\
159 $(TOOL_VCC100X86_CC) -E\
160 $(subst -Zi,-Z7,$(flags))\
161 $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
162 $(subst /,\\,$(abspath $(source))) \
163 --kObjCache-cc $(obj)\
164 $(TOOL_VCC100X86_CC) -c\
165 $(subst -Zi,-Z7,$(flags))\
166 -Fo$(obj)\
167 $(outbase).i
168 endef
169 else # !KBUILD_USE_KOBJCACHE
170 TOOL_VCC100X86_COMPILE_C_OUTPUT = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb)
171 TOOL_VCC100X86_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb)
172 ifdef TOOL_VCC100X86_KSUBMIT
173 define TOOL_VCC100X86_COMPILE_C_CMDS
151 TOOL_VCC100X86_COMPILE_C_OUTPUT =
152 TOOL_VCC100X86_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb)
153 ifdef TOOL_VCC100X86_KSUBMIT
154 TOOL_VCC100X86_COMPILE_C_DONT_PURGE_OUTPUT = 1 # speed
155 define TOOL_VCC100X86_COMPILE_C_CMDS
174156 $(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
175157 -- $(TOOL_VCC100X86_CC) -c\
176158 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
177159 -Fd$(outbase)-obj.pdb \
178 -FD\
179 -Fo$(obj)\
180 $(subst /,\\,$(abspath $(source)))
181 endef
182 else
183 define TOOL_VCC100X86_COMPILE_C_CMDS
160 -Fo$(obj)\
161 $(subst /,\\,$(abspath $(source)))
162 endef
163 else
164 define TOOL_VCC100X86_COMPILE_C_CMDS
184165 $(QUIET)$(TOOL_VCC100X86_CC) -c\
185166 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
186167 -Fd$(outbase)-obj.pdb \
187 -FD\
188 -Fo$(obj)\
189 $(subst /,\\,$(abspath $(source)))
190 $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100X86_PDB,$(outbase)-obj,idb)
191 endef
192 endif # !TOOL_VCC100X86_KSUBMIT
193 endif # !KBUILD_USE_KOBJCACHE
168 -Fo$(obj)\
169 $(subst /,\\,$(abspath $(source)))
170 $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
171 endef
172 endif # !TOOL_VCC100X86_KSUBMIT
194173
195174
196175 ## Compile C++ source.
206185 #
207186 # @param $(outbase) Output basename (full). Use this for list files and such.
208187 # @param $(objsuff) Object suffix.
209 TOOL_VCC100X86_COMPILE_CXX_DEPEND =
188 TOOL_VCC100X86_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE)
210189 TOOL_VCC100X86_COMPILE_CXX_DEPORD =
211 ifdef KBUILD_USE_KOBJCACHE
212 TOOL_VCC100X86_COMPILE_CXX_USES_KOBJCACHE = 1
213 TOOL_VCC100X86_COMPILE_CXX_OUTPUT = $(outbase).ii
214 TOOL_VCC100X86_COMPILE_CXX_OUTPUT_MAYBE =
215 define TOOL_VCC100X86_COMPILE_CXX_CMDS
216 $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -O2 -r\
217 --make-dep-fix-case --make-dep-gen-stubs --make-dep-quiet --make-dep-file $(dep)\
218 --kObjCache-cpp $(outbase).ii\
219 $(TOOL_VCC100X86_CXX) -E\
220 $(subst -Zi,-Z7,$(flags))\
221 $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
222 $(subst /,\\,$(abspath $(source))) \
223 --kObjCache-cc $(obj)\
224 $(TOOL_VCC100X86_CXX) -c\
225 $(subst -Zi,-Z7,$(flags))\
226 -Fo$(obj)\
227 $(outbase).ii
228 endef
229 else # !KBUILD_USE_KOBJCACHE
230 TOOL_VCC100X86_COMPILE_CXX_OUTPUT = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb)
231 TOOL_VCC100X86_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb)
232 ifdef TOOL_VCC100X86_KSUBMIT
233 define TOOL_VCC100X86_COMPILE_CXX_CMDS
190 TOOL_VCC100X86_COMPILE_CXX_OUTPUT =
191 TOOL_VCC100X86_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\
192 ,,$(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb))
193 ifdef TOOL_VCC100X86_KSUBMIT
194 TOOL_VCC100X86_COMPILE_CXX_DONT_PURGE_OUTPUT = 1 # speed
195 define TOOL_VCC100X86_COMPILE_CXX_CMDS
234196 $(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
235197 -- $(TOOL_VCC100X86_CXX) -c\
236198 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
237 -Fd$(outbase)-obj.pdb \
238 -FD\
239 -Fo$(obj)\
240 $(subst /,\\,$(abspath $(source)))
241 endef
242 else
243 define TOOL_VCC100X86_COMPILE_CXX_CMDS
199 $(if-expr defined($(target)_PCH_HDR)\
200 ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
201 -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
202 -Fo$(obj)\
203 $(subst /,\\,$(abspath $(source)))
204 endef
205 else
206 define TOOL_VCC100X86_COMPILE_CXX_CMDS
244207 $(QUIET)$(TOOL_VCC100X86_CXX) -c\
245208 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
246 -Fd$(outbase)-obj.pdb \
247 -FD\
248 -Fo$(obj)\
249 $(subst /,\\,$(abspath $(source)))
250 $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC100X86_PDB,$(outbase)-obj,idb)
251 endef
252 endif # !TOOL_VCC100X86_KSUBMIT
253 endif # !KBUILD_USE_KOBJCACHE
209 $(if-expr defined($(target)_PCH_HDR)\
210 ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\
211 -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \
212 -Fo$(obj)\
213 $(subst /,\\,$(abspath $(source)))
214 $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj)
215 endef
216 endif # !TOOL_VCC100X86_KSUBMIT
217
218
219 #
220 # Helper tool for creating the precompiled C++ header.
221 #
222 # It only have the C++ compile bits and it's purpose is to skip bits
223 # related _1_VCC_PCH_FILE and add -Yc.
224 #
225 TOOL_VCC100X86-PCH := Helper for creating precompiled header using CXX handling.
226 TOOL_VCC100X86-PCH_EXTENDS := VCC100X86
227 TOOL_VCC100X86-PCH_CXXOBJSUFF := .obj
228 TOOL_VCC100X86-PCH_CXXINCS = $(TOOL_VCC100X86_CXXINCS)
229 TOOL_VCC100X86-PCH_CXXFLAGS.debug = $(TOOL_VCC100X86_CXXFLAGS.debug)
230 TOOL_VCC100X86-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC100X86_CXXFLAGS.dbgopt)
231 TOOL_VCC100X86-PCH_CXXFLAGS.release = $(TOOL_VCC100X86_CXXFLAGS.release)
232 TOOL_VCC100X86-PCH_CXXFLAGS.profile = $(TOOL_VCC100X86_CXXFLAGS.profile)
233 TOOL_VCC100X86-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE)
234 TOOL_VCC100X86-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE)
235 TOOL_VCC100X86-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
236 TOOL_VCC100X86-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE)
237 ifdef TOOL_VCC100X86_KSUBMIT
238 define TOOL_VCC100X86-PCH_COMPILE_CXX_CMDS
239 $(QUIET)$(TOOL_VCC100X86_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
240 -- $(TOOL_VCC100X86_CXX) -c -Yc\
241 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
242 -Fp$($(target)_1_VCC_PCH_FILE) \
243 -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
244 -Fo$(obj)\
245 -TP \
246 $(subst /,\\,$(abspath $(source)))
247 endef
248 else
249 define TOOL_VCC100X86-PCH_COMPILE_CXX_CMDS
250 $(QUIET)$(TOOL_VCC100X86_CXX) -c -Yc\
251 $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
252 -Fp$($(target)_1_VCC_PCH_FILE) \
253 -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \
254 -Fo$(obj)\
255 -TP \
256 $(subst /,\\,$(abspath $(source)))
257 $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)
258
259 endef
260 endif # !TOOL_VCC100X86_KSUBMIT
261
254262
255263 ## @todo configure the assembler template.
256264
0 # $Id: qt4.kmk 2805 2016-01-28 11:08:44Z bird $
0 # $Id: qt4.kmk 2979 2016-09-27 14:36:32Z bird $
11 ## @file
22 # Qt 4 unit.
33 #
102102 endif
103103 ifeq ($(PATH_SDK_QT4),)
104104 PATH_SDK_QT4 := $(patsubst %/bin/rcc,%,$(firstword $(wildcard \
105 /usr/lib/*/qt4/bin/rcc \
105106 /usr/bin/rcc \
106107 /usr/local/bin/rcc \
107108 /usr/qt/4/bin/rcc \
114115 # Locate the include files.
115116 ifeq ($(PATH_SDK_QT4_INC),)
116117 PATH_SDK_QT4_INC := $(patsubst %/QtCore/qglobal.h,%,$(firstword $(wildcard \
118 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/include/$(type)/qt4/QtCore/qglobal.h) \
117119 $(PATH_SDK_QT4)/include/QtCore/qglobal.h \
118120 $(PATH_SDK_QT4)/include/qt4/QtCore/qglobal.h \
119121 /usr/include/qt4/QtCore/qtglobal.h \
131133 $(PATH_SDK_QT4)/lib32/qt4/libQtCore$(SUFF_DLL) \
132134 /usr/lib32/libQtCore$(SUFF_DLL) \
133135 /usr/lib32/qt4/libQtCore$(SUFF_DLL) \
134 /usr/lib/i386-linux-gnu/libQtCore$(SUFF_DLL) \
136 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \
135137 /usr/local/lib32/libQtCore$(SUFF_DLL) \
136138 /usr/local/lib32/qt4/libQtCore$(SUFF_DLL) \
137 /usr/local/lib/i386-linux-gnu/libQtCore$(SUFF_DLL) \
139 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \
138140 $(PATH_SDK_QT4)/lib/libQtCore$(SUFF_DLL) \
139141 $(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \
140142 $(PATH_SDK_QT4)/lib/i386-linux-gnu/libQtCore$(SUFF_DLL) \
151153 /usr/lib64/libQtCore$(SUFF_DLL) \
152154 /usr/lib64/qt4/libQtCore$(SUFF_DLL) \
153155 /usr/lib/amd64/libQtCore$(SUFF_DLL) \
154 /usr/lib/x86_64-linux-gnu/libQtCore$(SUFF_DLL) \
156 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \
155157 /usr/local/lib64/libQtCore$(SUFF_DLL) \
156158 /usr/local/lib64/qt4/libQtCore$(SUFF_DLL) \
157159 /usr/local/lib/amd64/libQtCore$(SUFF_DLL) \
158 /usr/local/lib/x86_64-linux-gnu/libQtCore$(SUFF_DLL) \
160 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \
159161 $(PATH_SDK_QT4)/lib/libQtCore$(SUFF_DLL) \
160162 $(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \
161163 $(PATH_SDK_QT4)/lib/x86_64-linux-gnu/libQtCore$(SUFF_DLL) \
174176 $(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \
175177 /usr/lib/libQtCore$(SUFF_DLL) \
176178 /usr/lib/qt4/libQtCore$(SUFF_DLL) \
179 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \
177180 /usr/local/lib/libQtCore$(SUFF_DLL) \
178181 /usr/local/lib/qt4/libQtCore$(SUFF_DLL) \
182 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \
179183 )))
180184 endif
181185 ifneq ($(PATH_SDK_QT4_LIB),)
240244 ifdef TOOL_QT4_BIN_SUFF
241245 TOOL_QT4_BIN_SUFF := $(TOOL_QT4_BIN_SUFF)
242246 endif
243 # Try looking for moc-qt4 / moc-$(suffix) first.
247 # Try looking for moc-$(suffix) first, if specified.
244248 ifneq ($(TOOL_QT4_BIN_SUFF),)
245249 PATH_TOOL_QT4_BIN := $(patsubst %/moc$(TOOL_QT4_BIN_SUFF),%,$(firstword $(wildcard \
250 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc$(TOOL_QT4_BIN_SUFF)) \
246251 /usr/lib/qt4/bin/moc$(TOOL_QT4_BIN_SUFF) \
247252 /usr/qt/4/bin/moc$(TOOL_QT4_BIN_SUFF) \
248253 /usr/share/qt4/bin/moc$(TOOL_QT4_BIN_SUFF) \
250255 /usr/bin/moc$(TOOL_QT4_BIN_SUFF) \
251256 )))
252257 else
253 PATH_TOOL_QT4_BIN := $(patsubst %/moc-qt4,%,$(firstword $(wildcard \
258 # No suffix given, so before we check out -qt4 look at qt4 specific locations to avoid choosers and symlinks.
259 PATH_TOOL_QT4_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
260 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc) \
261 $(if $(intersects $(KBUILD_HOST_ARCH), $(KBUILD_ARCHES_64)),/usr/lib64/qt4/bin/moc,) \
262 /usr/lib/qt4/bin/moc \
263 /usr/local/lib/qt4/bin/moc \
264 /usr/qt/4/bin/moc \
265 /usr/local/qt/4/bin/moc \
266 /usr/share/qt4/bin/moc \
267 /usr/local/share/qt4/bin/moc \
268 )))
269 ifeq ($(PATH_TOOL_QT4_BIN),)
270 PATH_TOOL_QT4_BIN := $(patsubst %/moc-qt4,%,$(firstword $(wildcard \
271 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc-qt4) \
254272 /usr/lib/qt4/bin/moc-qt4 \
255273 /usr/qt/4/bin/moc-qt4 \
256274 /usr/share/qt4/bin/moc-qt4 \
257275 /usr/local/bin/moc-qt4 \
258276 /usr/bin/moc-qt4 \
259277 )))
260 ifneq ($(PATH_TOOL_QT4_BIN),)
261 TOOL_QT4_BIN_SUFF := -qt4
262 else
263 # If no luck, try looking for moc in the qt4 specific locations.
264 PATH_TOOL_QT4_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
265 /usr/lib/qt4/bin/moc \
266 /usr/qt/4/bin/moc \
267 /usr/share/qt4/bin/moc \
268 )))
278 ifneq ($(PATH_TOOL_QT4_BIN),)
279 TOOL_QT4_BIN_SUFF := -qt4
280 endif
269281 endif
270282 endif
271283 # If still no go, try looking for qt3to4 and rcc.
272284 ifeq ($(PATH_TOOL_QT4_BIN),)
273285 PATH_TOOL_QT4_BIN := $(patsubst %/qt3to4,%,$(firstword $(wildcard \
286 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/qt3to4) \
274287 /usr/lib/qt4/bin/qt3to4 \
275288 /usr/qt/4/bin/qt3to4 \
276289 /usr/share/qt4/bin/qt3to4 \
280293 endif
281294 ifeq ($(PATH_TOOL_QT4_BIN),)
282295 PATH_TOOL_QT4_BIN := $(patsubst %/rcc$(TOOL_QT4_BIN_SUFF),%,$(firstword $(wildcard \
296 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF)) \
283297 /usr/lib/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF) \
284298 /usr/qt/4/bin/rcc$(TOOL_QT4_BIN_SUFF) \
285299 /usr/share/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF) \
289303 endif
290304 if "$(PATH_TOOL_QT4_BIN)" == "" && "$(TOOL_QT4_BIN_SUFF)" != ""
291305 PATH_TOOL_QT4_BIN := $(patsubst %/rcc,%,$(firstword $(wildcard \
306 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/rcc) \
292307 /usr/lib/qt4/bin/rcc \
293308 /usr/qt/4/bin/rcc \
294309 /usr/share/qt4/bin/rcc \
320335 # Pathless, relies on the environment.
321336 TOOL_QT4_MOC ?= moc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
322337 TOOL_QT4_UIC ?= uic$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
323 TOOL_QT4_RCC ?= rcc$(HOST_SUFF_EXE)
338 TOOL_QT4_RCC ?= rcc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
324339 TOOL_QT4_LRC ?= lrelease$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
325340 TOOL_QT4_LUPDATE ?= lupdate$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE)
326341 endif
0 # $Id: qt5.kmk 2807 2016-01-28 13:21:41Z bird $
0 # $Id: qt5.kmk 2980 2016-09-27 14:40:53Z bird $
11 ## @file
22 # Qt 5 unit.
33 #
102102 endif
103103 ifeq ($(PATH_SDK_QT5),)
104104 PATH_SDK_QT5 := $(patsubst %/bin/rcc,%,$(firstword $(wildcard \
105 /usr/lib/*/qt5/bin/rcc \
105106 /usr/bin/rcc \
106107 /usr/local/bin/rcc \
107108 /usr/qt/5/bin/rcc \
114115 # Locate the include files.
115116 ifeq ($(PATH_SDK_QT5_INC),)
116117 PATH_SDK_QT5_INC := $(patsubst %/QtCore/qglobal.h,%,$(firstword $(wildcard \
117 $(PATH_SDK_QT5)/include/QtCore/qglobal.h \
118 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/include/$(type)/qt5/QtCore/qglobal.h) \
118119 $(PATH_SDK_QT5)/include/qt5/QtCore/qglobal.h \
119120 /usr/include/qt5/QtCore/qtglobal.h \
120121 /usr/local/include/qt5/QtCore/qtglobal.h \
122 $(PATH_SDK_QT5)/include/QtCore/qglobal.h \
121123 )))
122124 ifneq ($(PATH_SDK_QT5_INC),)
123125 export PATH_SDK_QT5_INC
131133 $(PATH_SDK_QT5)/lib32/qt5/libQt5Core$(SUFF_DLL) \
132134 /usr/lib32/libQt5Core$(SUFF_DLL) \
133135 /usr/lib32/qt5/libQt5Core$(SUFF_DLL) \
134 /usr/lib/i386-linux-gnu/libQt5Core$(SUFF_DLL) \
136 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \
135137 /usr/local/lib32/libQt5Core$(SUFF_DLL) \
136138 /usr/local/lib32/qt5/libQt5Core$(SUFF_DLL) \
137 /usr/local/lib/i386-linux-gnu/libQt5Core$(SUFF_DLL) \
139 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \
138140 $(PATH_SDK_QT5)/lib/libQt5Core$(SUFF_DLL) \
139141 $(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \
140142 $(PATH_SDK_QT5)/lib/i386-linux-gnu/libQt5Core$(SUFF_DLL) \
151153 /usr/lib64/libQt5Core$(SUFF_DLL) \
152154 /usr/lib64/qt5/libQt5Core$(SUFF_DLL) \
153155 /usr/lib/amd64/libQt5Core$(SUFF_DLL) \
154 /usr/lib/x86_64-linux-gnu/libQt5Core$(SUFF_DLL) \
156 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \
155157 /usr/local/lib64/libQt5Core$(SUFF_DLL) \
156158 /usr/local/lib64/qt5/libQt5Core$(SUFF_DLL) \
157159 /usr/local/lib/amd64/libQt5Core$(SUFF_DLL) \
158 /usr/local/lib/x86_64-linux-gnu/libQt5Core$(SUFF_DLL) \
160 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \
159161 $(PATH_SDK_QT5)/lib/libQt5Core$(SUFF_DLL) \
160162 $(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \
161163 $(PATH_SDK_QT5)/lib/x86_64-linux-gnu/libQt5Core$(SUFF_DLL) \
174176 $(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \
175177 /usr/lib/libQt5Core$(SUFF_DLL) \
176178 /usr/lib/qt5/libQt5Core$(SUFF_DLL) \
179 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \
177180 /usr/local/lib/libQt5Core$(SUFF_DLL) \
178181 /usr/local/lib/qt5/libQt5Core$(SUFF_DLL) \
182 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \
179183 )))
180184 endif
181185 ifneq ($(PATH_SDK_QT5_LIB),)
243247 # Try looking for moc-qt5 / moc-$(suffix) first.
244248 ifneq ($(TOOL_QT5_BIN_SUFF),)
245249 PATH_TOOL_QT5_BIN := $(patsubst %/moc$(TOOL_QT5_BIN_SUFF),%,$(firstword $(wildcard \
250 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc$(TOOL_QT5_BIN_SUFF)) \
246251 /usr/lib/qt5/bin/moc$(TOOL_QT5_BIN_SUFF) \
247252 /usr/qt/5/bin/moc$(TOOL_QT5_BIN_SUFF) \
248253 /usr/share/qt5/bin/moc$(TOOL_QT5_BIN_SUFF) \
250255 /usr/bin/moc$(TOOL_QT5_BIN_SUFF) \
251256 )))
252257 else
253 PATH_TOOL_QT5_BIN := $(patsubst %/moc-qt5,%,$(firstword $(wildcard \
258 # No suffix given, so before we check out -qt5 look at qt5 specific locations to avoid choosers and symlinks.
259 PATH_TOOL_QT5_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
260 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc) \
261 $(if $(intersects $(KBUILD_HOST_ARCH), $(KBUILD_ARCHES_64)),/usr/lib64/qt5/bin/moc,) \
262 /usr/lib/qt5/bin/moc \
263 /usr/local/lib/qt5/bin/moc \
264 /usr/qt/5/bin/moc \
265 /usr/local/qt/5/bin/moc \
266 /usr/share/qt5/bin/moc \
267 /usr/local/share/qt5/bin/moc \
268 )))
269 ifeq ($(PATH_TOOL_QT5_BIN),)
270 PATH_TOOL_QT5_BIN := $(patsubst %/moc-qt5,%,$(firstword $(wildcard \
271 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc-qt5) \
254272 /usr/lib/qt5/bin/moc-qt5 \
255273 /usr/qt/5/bin/moc-qt5 \
256274 /usr/share/qt5/bin/moc-qt5 \
257275 /usr/local/bin/moc-qt5 \
258276 /usr/bin/moc-qt5 \
259277 )))
260 ifneq ($(PATH_TOOL_QT5_BIN),)
261 TOOL_QT5_BIN_SUFF := -qt5
262 else
263 # If no luck, try looking for moc in the qt5 specific locations.
264 PATH_TOOL_QT5_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \
265 /usr/lib/qt5/bin/moc \
266 /usr/qt/5/bin/moc \
267 /usr/share/qt5/bin/moc \
268 )))
278 ifneq ($(PATH_TOOL_QT5_BIN),)
279 TOOL_QT5_BIN_SUFF := -qt5
280 endif
269281 endif
270282 endif
271283 # If still no go, try looking for qt4to5 and rcc.
272284 ifeq ($(PATH_TOOL_QT5_BIN),)
273285 PATH_TOOL_QT5_BIN := $(patsubst %/qt4to5,%,$(firstword $(wildcard \
286 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/qt4to5) \
274287 /usr/lib/qt5/bin/qt4to5 \
275288 /usr/qt/5/bin/qt4to5 \
276289 /usr/share/qt5/bin/qt4to5 \
280293 endif
281294 ifeq ($(PATH_TOOL_QT5_BIN),)
282295 PATH_TOOL_QT5_BIN := $(patsubst %/rcc$(TOOL_QT5_BIN_SUFF),%,$(firstword $(wildcard \
296 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF)) \
283297 /usr/lib/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF) \
284298 /usr/qt/5/bin/rcc$(TOOL_QT5_BIN_SUFF) \
285299 /usr/share/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF) \
289303 endif
290304 if "$(PATH_TOOL_QT5_BIN)" == "" && "$(TOOL_QT5_BIN_SUFF)" != ""
291305 PATH_TOOL_QT5_BIN := $(patsubst %/rcc,%,$(firstword $(wildcard \
306 $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/rcc) \
292307 /usr/lib/qt5/bin/rcc \
293308 /usr/qt/5/bin/rcc \
294309 /usr/share/qt5/bin/rcc \
306321 PATH_TOOL_QT5_BIN := $(PATH_TOOL_QT5_BIN)
307322 endif
308323 ifneq ($(PATH_TOOL_QT5_BIN),)
309 TOOL_QT5_MOC ?= $(PATH_TOOL_QT5_BIN)/moc$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
310 TOOL_QT5_UIC ?= $(PATH_TOOL_QT5_BIN)/uic$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
324 TOOL_QT5_MOC ?= $(PATH_TOOL_QT5_BIN)/moc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
325 TOOL_QT5_UIC ?= $(PATH_TOOL_QT5_BIN)/uic$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
311326 ifndef TOOL_QT5_RCC
312 TOOL_QT5_RCC := $(PATH_TOOL_QT5_BIN)/rcc$(HOST_SUFF_EXE)
327 TOOL_QT5_RCC := $(PATH_TOOL_QT5_BIN)/rcc$(HOSTSUFF_EXE)
313328 ifeq ($(wildcard $(TOOL_QT5_RCC)),)
314 TOOL_QT5_RCC := $(PATH_TOOL_QT5_BIN)/rcc$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
329 TOOL_QT5_RCC := $(PATH_TOOL_QT5_BIN)/rcc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
315330 endif
316331 endif
317 TOOL_QT5_LRC ?= $(PATH_TOOL_QT5_BIN)/lrelease$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
318 TOOL_QT5_LUPDATE ?= $(PATH_TOOL_QT5_BIN)/lupdate$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
332 TOOL_QT5_LRC ?= $(PATH_TOOL_QT5_BIN)/lrelease$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
333 TOOL_QT5_LUPDATE ?= $(PATH_TOOL_QT5_BIN)/lupdate$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
319334 else
320335 # Pathless, relies on the environment.
321 TOOL_QT5_MOC ?= moc$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
322 TOOL_QT5_UIC ?= uic$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
323 TOOL_QT5_RCC ?= rcc$(HOST_SUFF_EXE)
324 TOOL_QT5_LRC ?= lrelease$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
325 TOOL_QT5_LUPDATE ?= lupdate$(TOOL_QT5_BIN_SUFF)$(HOST_SUFF_EXE)
336 TOOL_QT5_MOC ?= moc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
337 TOOL_QT5_UIC ?= uic$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
338 TOOL_QT5_RCC ?= rcc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
339 TOOL_QT5_LRC ?= lrelease$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
340 TOOL_QT5_LUPDATE ?= lupdate$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE)
341 endif
342 ifdef TOOL_QT5_USE_KSUBMIT
343 ifeq ($(KBUILD_HOST),win)
344 TOOL_QT5_MOC_KSUBMIT ?= kmk_builtin_kSubmit --$(SP)
345 endif
326346 endif
327347
328348 # General Properties used by kBuild and/or units/qt.kmk
350370 TOOL_QT5_MOC_CPP_OUTPUT =
351371 TOOL_QT5_MOC_CPP_OUTPUT_MAYBE =
352372 define TOOL_QT5_MOC_CPP_CMDS
353 $(QUIET)$(TOOL_QT5_MOC)\
373 $(QUIET)$(TOOL_QT5_MOC_KSUBMIT)$(TOOL_QT5_MOC)\
354374 $(flags)\
355375 $(addprefix -I, $(incs))\
356376 $(addprefix -D, $(defs))\
373393 TOOL_QT5_MOC_HPP_OUTPUT =
374394 TOOL_QT5_MOC_HPP_OUTPUT_MAYBE =
375395 define TOOL_QT5_MOC_HPP_CMDS
376 $(QUIET)$(TOOL_QT5_MOC)\
396 $(QUIET)$(TOOL_QT5_MOC_KSUBMIT)$(TOOL_QT5_MOC)\
377397 $(flags)\
378398 $(addprefix -I, $(incs))\
379399 $(addprefix -D, $(defs))\
0 # $Id: vccprecomp.kmk 2956 2016-09-21 19:37:20Z bird $
1 ## @file
2 # kBuild Unit - Target Level Precompiled Headers for Visual C++.
3 #
4
5 #
6 # Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spam-xiv@anduin.net>
7 #
8 # This file is part of kBuild.
9 #
10 # kBuild is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
14 #
15 # kBuild is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with kBuild; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #
24 #
25 # As a special exception you are granted permission to include this file, via
26 # the kmk include directive, as you wish without this in itself causing the
27 # resulting makefile, program or whatever to be covered by the GPL license.
28 # This exception does not however invalidate any other reasons why the makefile,
29 # program, whatever should not be covered the GPL.
30 #
31 #
32
33
34 UNIT_vccprecomp = Target level precompiled Headers for Visual C++
35
36 #
37 # Early target processing pass #1.
38 #
39 # This set the internal _VCC_PCH_FILE and VCC_COMMON_OBJ_PDB properties,
40 # which will be picked up by the VCCxxx tool.
41 #
42 define def_unit_vccprecomp_target_pre
43 $(target)_1_VCC_PCH_FILE := $(outbase)-pch.pch
44 $(target)_1_VCC_COMMON_OBJ_PDB := $(outbase)-common-obj.pdb
45 endef
46
47 #
48 # Early target processing pass #2.
49 #
50 # This sets up a rule for creating the .pch file after qt5 and similar units
51 # are done modifying INCS, DEFS and company. The 'tool' variable is defined by
52 # footer-pass2-compiling-targets.kmk and is really the LD tool, but that'll
53 # have to do for now. The '-PCH' variant of the VCC tool, is defined together
54 # with $(tool) and allow us to bypass the options and dependencies triggered
55 # by _1_VCC_PCH_FILE, _1_VCC_COMMON_OBJ_PDB and _PCH_HDR, and also make sure we
56 # don't get circular dependencies by way of kDepObj and the debug info.
57 #
58 define def_unit_vccprecomp_target_pre_2
59 local source := $($(target)_PCH_HDR)
60 $(source)_TOOL := $(tool)-PCH
61 local suff := $(suffix $(source))
62 local type := CXX
63 $(kb-src-one 2)
64 endef
65
0 /* $Id: kDepPre.c 2413 2010-09-11 17:43:04Z bird $ */
0 /* $Id: kDepPre.c 2955 2016-09-21 19:05:53Z bird $ */
11 /** @file
22 * kDepPre - Dependency Generator using Precompiler output.
33 */
463463 */
464464 if (!i)
465465 {
466 depOptimize(fFixCase, 0 /* fQuiet */);
466 depOptimize(fFixCase, 0 /* fQuiet */, NULL /*pszIgnoredExt*/);
467467 fprintf(pOutput, "%s:", pszTarget);
468468 depPrint(pOutput);
469469 if (fStubs)
0 /* $Id: kObjCache.c 2627 2012-08-09 14:12:12Z bird $ */
0 /* $Id: kObjCache.c 2955 2016-09-21 19:05:53Z bird $ */
11 /** @file
22 * kObjCache - Object Cache.
33 */
10991099 if (!pFile)
11001100 FatalMsg("Failed to open dependency file '%s': %s\n", pszFilename, strerror(errno));
11011101
1102 depOptimize(fFixCase, fQuiet);
1102 depOptimize(fFixCase, fQuiet, NULL /*pszIgnoredExt*/);
11031103
11041104 /* Make object file name with unix slashes. */
11051105 pszObjFileAbs = MakePathFromDirAndFile(pszObjFile, pszObjDir);
50865086 }
50875087 else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version"))
50885088 {
5089 printf("kObjCache - kBuild version %d.%d.%d ($Revision: 2627 $)\n"
5089 printf("kObjCache - kBuild version %d.%d.%d ($Revision: 2955 $)\n"
50905090 "Copyright (c) 2007-2012 knut st. osmundsen\n",
50915091 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
50925092 return 0;
0 # $Id: Makefile.kmk 2894 2016-09-08 13:27:56Z bird $
0 # $Id: Makefile.kmk 2968 2016-09-26 18:14:50Z bird $
11 ## @file
22 # Sub-makefile for kWorker.
33 #
2929
3030 PROGRAMS += kWorker
3131 kWorker_TEMPLATE = BIN-STATIC-THREADED
32 kWorker_DEFS := KWORKER
3233 kWorker_DEFS.debug = K_STRICT
3334 kWorker_DEFS.release = NASSERT
3435 kWorker_SOURCES = \
4647 $(PATH_SDK_WINDDK71_LIB_WNET)/ntdll.lib \
4748 $(PATH_SDK_WINDDK71_LIB_WNET)/psapi.lib
4849 kWorker_LDFLAGS.win = \
49 /BASE:0x10000 /DYNAMICBASE:NO /FIXED /SECTION:DefLdBuf,EWR
50 /BASE:0x10000 /DYNAMICBASE:NO /FIXED
51 #kWorker_LDFLAGS.win.x86 = \
52 # /SAFESEH:NO - doesn't help anyone.
5053
5154
5255 #
5659 kWorkerLib_TEMPLATE = LIB-STATIC-THREADED
5760 kWorkerLib_DEFPATH = ../lib # Need fix from r2837.
5861 kWorkerLib_DEFPATH := $(PATH_SUB_CURRENT)/../lib
62 kWorkerLib_DEFS := KWORKER
5963 kWorkerLib_SOURCES = \
6064 crc32.c \
6165 md5.c \
7175 nt/ntstat.c \
7276 nt/ntunlink.c \
7377 nt/kFsCache.c \
74 quote_argv.c
78 quote_argv.c \
79 maybe_con_write.c \
80 maybe_con_fwrite.c \
81 msc_buffered_printf.c
7582 kbuild_version.c_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV)
7683
7784 #
0 /* $Id: kWorker.c 2906 2016-09-09 22:15:57Z bird $ */
0 /* $Id: kWorker.c 2987 2016-11-01 18:27:39Z bird $ */
11 /** @file
22 * kWorker - experimental process reuse worker for Windows.
33 *
3030 * Header Files *
3131 *********************************************************************************************************************************/
3232 //#undef NDEBUG
33 //#define K_STRICT 1
34 //#define KW_LOG_ENABLED
35
3336 #define PSAPI_VERSION 1
3437 #include <k/kHlp.h>
3538 #include <k/kLdr.h>
3942 #include <setjmp.h>
4043 #include <ctype.h>
4144 #include <errno.h>
45 #include <process.h>
4246
4347 #include "nt/ntstat.h"
4448 #include "kbuild_version.h"
45 /* lib/nt_fullpath.c */
46 extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
4749
4850 #include "nt/ntstuff.h"
4951 #include <psapi.h>
5052
5153 #include "nt/kFsCache.h"
54 #include "nt_fullpath.h"
5255 #include "quote_argv.h"
5356 #include "md5.h"
5457
6871 * they are included. */
6972 #define WITH_HASH_MD5_CACHE
7073
74 /** @def WITH_CRYPT_CTX_REUSE
75 * Enables reusing crypt contexts. The Visual C++ compiler always creates a
76 * context which is only used for MD5 and maybe some random bytes (VS 2010).
77 * So, only create it once and add a reference to it instead of creating new
78 * ones. Saves registry access among other things. */
79 #define WITH_CRYPT_CTX_REUSE
80
7181 /** @def WITH_CONSOLE_OUTPUT_BUFFERING
7282 * Enables buffering of all console output as well as removal of annoying
7383 * source file echo by cl.exe. */
7484 #define WITH_CONSOLE_OUTPUT_BUFFERING
7585
76
77 /** String constant comma length. */
78 #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1
86 /** @def WITH_STD_OUT_ERR_BUFFERING
87 * Enables buffering of standard output and standard error buffer as well as
88 * removal of annoying source file echo by cl.exe. */
89 #define WITH_STD_OUT_ERR_BUFFERING
90
91 /** @def WITH_LOG_FILE
92 * Log to file instead of stderr. */
93 #define WITH_LOG_FILE
94
95 /** @def WITH_HISTORY
96 * Keep history of the last jobs. For debugging. */
97 #define WITH_HISTORY
98
99 /** @def WITH_FIXED_VIRTUAL_ALLOCS
100 * Whether to pre allocate memory for known fixed VirtualAlloc calls (currently
101 * there is only one, but an important one, from cl.exe).
102 */
103 #if K_ARCH == K_ARCH_X86_32
104 # define WITH_FIXED_VIRTUAL_ALLOCS
105 #endif
106
107 /** @def WITH_PCH_CACHING
108 * Enables read caching of precompiled header files. */
109 #if K_ARCH_BITS >= 64
110 # define WITH_PCH_CACHING
111 #endif
112
113
114 #ifndef NDEBUG
115 # define KW_LOG_ENABLED
116 #endif
79117
80118 /** @def KW_LOG
81119 * Generic logging.
82120 * @param a Argument list for kwDbgPrintf */
83 #ifndef NDEBUG
121 #ifdef KW_LOG_ENABLED
84122 # define KW_LOG(a) kwDbgPrintf a
85123 #else
86124 # define KW_LOG(a) do { } while (0)
87125 #endif
88126
127 /** @def KWLDR_LOG
128 * Loader related logging.
129 * @param a Argument list for kwDbgPrintf */
130 #ifdef KW_LOG_ENABLED
131 # define KWLDR_LOG(a) kwDbgPrintf a
132 #else
133 # define KWLDR_LOG(a) do { } while (0)
134 #endif
135
136
89137 /** @def KWFS_LOG
90138 * FS cache logging.
91139 * @param a Argument list for kwDbgPrintf */
92 #ifndef NDEBUG
140 #ifdef KW_LOG_ENABLED
93141 # define KWFS_LOG(a) kwDbgPrintf a
94142 #else
95143 # define KWFS_LOG(a) do { } while (0)
96144 #endif
97145
146 /** @def KWOUT_LOG
147 * Output related logging.
148 * @param a Argument list for kwDbgPrintf */
149 #ifdef KW_LOG_ENABLED
150 # define KWOUT_LOG(a) kwDbgPrintf a
151 #else
152 # define KWOUT_LOG(a) do { } while (0)
153 #endif
154
98155 /** @def KWCRYPT_LOG
99156 * FS cache logging.
100157 * @param a Argument list for kwDbgPrintf */
101 #ifndef NDEBUG
158 #ifdef KW_LOG_ENABLED
102159 # define KWCRYPT_LOG(a) kwDbgPrintf a
103160 #else
104161 # define KWCRYPT_LOG(a) do { } while (0)
121178
122179 /** Marks unfinished code. */
123180 #if 1
124 # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); __debugbreak(); } while (0)
181 # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); __debugbreak(); } while (0)
125182 #else
126 # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); } while (0)
183 # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); } while (0)
127184 #endif
128185
129186 /** User data key for tools. */
130187 #define KW_DATA_KEY_TOOL (~(KUPTR)16381)
131188 /** User data key for a cached file. */
132189 #define KW_DATA_KEY_CACHED_FILE (~(KUPTR)65521)
190
191 /** String constant comma length. */
192 #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1
133193
134194
135195 /*********************************************************************************************************************************
187247 struct
188248 {
189249 /** Where we load the image. */
190 void *pvLoad;
250 KU8 *pbLoad;
191251 /** Virgin copy of the image. */
192 void *pvCopy;
252 KU8 *pbCopy;
193253 /** Ldr pvBits argument. This is NULL till we've successfully resolved
194254 * the imports. */
195255 void *pvBits;
205265 #endif
206266 /** Set if we share memory with other executables. */
207267 KBOOL fUseLdBuf;
268 /** Set after the first whole image copy is done. */
269 KBOOL fCanDoQuick;
270 /** Number of quick copy chunks. */
271 KU8 cQuickCopyChunks;
272 /** Number of quick zero chunks. */
273 KU8 cQuickZeroChunks;
274 /** Quicker image copy instructions that skips non-writable parts when
275 * possible. Need to check fCanDoQuick, fUseLdBuf and previous executable
276 * image. */
277 struct
278 {
279 /** The copy destination. */
280 KU8 *pbDst;
281 /** The copy source. */
282 KU8 const *pbSrc;
283 /** How much to copy. */
284 KSIZE cbToCopy;
285 } aQuickCopyChunks[3];
286 /** For handling BSS and zero alignment padding when using aQuickCopyChunks. */
287 struct
288 {
289 /** Where to start zeroing. */
290 KU8 *pbDst;
291 /** How much to zero. */
292 KSIZE cbToZero;
293 } aQuickZeroChunks[3];
208294 /** Number of imported modules. */
209295 KSIZE cImpMods;
210296 /** Import array (variable size). */
259345
260346 /** Cached file handle. */
261347 HANDLE hCached;
348 /** Cached file section handle. */
349 HANDLE hSection;
262350 /** Cached file content. */
263351 KU8 *pbCached;
264352 /** The file size. */
352440 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
353441
354442 /**
355 * Console line buffer.
356 */
357 typedef struct KWCONSOLEOUTPUTLINE
443 * Console line buffer or output full buffer.
444 */
445 typedef struct KWOUTPUTSTREAMBUF
358446 {
359447 /** The main output handle. */
360448 HANDLE hOutput;
361449 /** Our backup handle. */
362450 HANDLE hBackup;
363 /** Set if this is a console handle. */
451 /** Set if this is a console handle and we're in line buffered mode.
452 * When clear, we may buffer multiple lines, though try flush on line
453 * boundraries when ever possible. */
364454 KBOOL fIsConsole;
365 /** Amount of pending console output in wchar_t's. */
366 KU32 cwcBuf;
367 /** The allocated buffer size. */
368 KU32 cwcBufAlloc;
369 /** Pending console output. */
370 wchar_t *pwcBuf;
371 } KWCONSOLEOUTPUTLINE;
455 /** Compressed GetFileType result. */
456 KU8 fFileType;
457 KU8 abPadding[2];
458 union
459 {
460 /** Line buffer mode (fIsConsole == K_TRUE). */
461 struct
462 {
463 /** Amount of pending console output in wchar_t's. */
464 KU32 cwcBuf;
465 /** The allocated buffer size. */
466 KU32 cwcBufAlloc;
467 /** Pending console output. */
468 wchar_t *pwcBuf;
469 } Con;
470 /** Fully buffered mode (fIsConsole == K_FALSE). */
471 struct
472 {
473 /** Amount of pending output (in chars). */
474 KU32 cchBuf;
475 #ifdef WITH_STD_OUT_ERR_BUFFERING
476 /** The allocated buffer size (in chars). */
477 KU32 cchBufAlloc;
478 /** Pending output. */
479 char *pchBuf;
480 #endif
481 } Fully;
482 } u;
483 } KWOUTPUTSTREAMBUF;
372484 /** Pointer to a console line buffer. */
373 typedef KWCONSOLEOUTPUTLINE *PKWCONSOLEOUTPUTLINE;
485 typedef KWOUTPUTSTREAMBUF *PKWOUTPUTSTREAMBUF;
374486
375487 /**
376488 * Combined console buffer of complete lines.
400512 {
401513 KWHANDLETYPE_INVALID = 0,
402514 KWHANDLETYPE_FSOBJ_READ_CACHE,
515 KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING,
403516 KWHANDLETYPE_TEMP_FILE,
404 KWHANDLETYPE_TEMP_FILE_MAPPING
405 //KWHANDLETYPE_CONSOLE_CACHE
517 KWHANDLETYPE_TEMP_FILE_MAPPING,
518 KWHANDLETYPE_OUTPUT_BUF
406519 } KWHANDLETYPE;
407520
408521 /** Handle data. */
409522 typedef struct KWHANDLE
410523 {
411524 KWHANDLETYPE enmType;
525 /** Number of references */
526 KU32 cRefs;
412527 /** The current file offset. */
413528 KU32 offFile;
414529 /** Handle access. */
423538 PKFSWCACHEDFILE pCachedFile;
424539 /** Temporary file handle or mapping handle. */
425540 PKWFSTEMPFILE pTempFile;
541 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
542 /** Buffered output stream. */
543 PKWOUTPUTSTREAMBUF pOutBuf;
544 #endif
426545 } u;
427546 } KWHANDLE;
428547 typedef KWHANDLE *PKWHANDLE;
548
549 /**
550 * Tracking one of our memory mappings.
551 */
552 typedef struct KWMEMMAPPING
553 {
554 /** Number of references. */
555 KU32 cRefs;
556 /** The mapping type (KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING or
557 * KWHANDLETYPE_TEMP_FILE_MAPPING). */
558 KWHANDLETYPE enmType;
559 /** The mapping address. */
560 PVOID pvMapping;
561 /** Type specific data. */
562 union
563 {
564 /** The file system object. */
565 PKFSWCACHEDFILE pCachedFile;
566 /** Temporary file handle or mapping handle. */
567 PKWFSTEMPFILE pTempFile;
568 } u;
569 } KWMEMMAPPING;
570 /** Pointer to a memory mapping tracker. */
571 typedef KWMEMMAPPING *PKWMEMMAPPING;
429572
430573
431574 /** Pointer to a VirtualAlloc tracker entry. */
438581 PKWVIRTALLOC pNext;
439582 void *pvAlloc;
440583 KSIZE cbAlloc;
584 /** This is KU32_MAX if not a preallocated chunk. */
585 KU32 idxPreAllocated;
441586 } KWVIRTALLOC;
442587
443588
556701 int rcExitCode;
557702 /** Set if we're running. */
558703 KBOOL fRunning;
704 /** Whether to disable caching of ".pch" files. */
705 KBOOL fNoPchCaching;
559706
560707 /** The command line. */
561708 char *pszCmdLine;
596743 KU32 cHandles;
597744 /** Number of active handles in the table. */
598745 KU32 cActiveHandles;
746 /** Number of handles in the handle table that will not be freed. */
747 KU32 cFixedHandles;
748 /** Total number of leaked handles. */
749 KU32 cLeakedHandles;
750
751 /** Number of active memory mappings in paMemMappings. */
752 KU32 cMemMappings;
753 /** The allocated size of paMemMappings. */
754 KU32 cMemMappingsAlloc;
755 /** Memory mappings (MapViewOfFile / UnmapViewOfFile). */
756 PKWMEMMAPPING paMemMappings;
599757
600758 /** Head of the list of temporary file. */
601759 PKWFSTEMPFILE pTempFileHead;
614772 * This is only done from images we forcibly restore. */
615773 PKWEXITCALLACK pExitCallbackHead;
616774
617 UNICODE_STRING SavedCommandLine;
775 MY_UNICODE_STRING SavedCommandLine;
618776
619777 #ifdef WITH_HASH_MD5_CACHE
620778 /** The special MD5 hash instance. */
638796 } LastHashRead;
639797 #endif
640798
799 #ifdef WITH_CRYPT_CTX_REUSE
800 /** Reusable crypt contexts. */
801 struct
802 {
803 /** The creation provider type. */
804 KU32 dwProvType;
805 /** The creation flags. */
806 KU32 dwFlags;
807 /** The length of the container name. */
808 KU32 cwcContainer;
809 /** The length of the provider name. */
810 KU32 cwcProvider;
811 /** The container name string. */
812 wchar_t *pwszContainer;
813 /** The provider name string. */
814 wchar_t *pwszProvider;
815 /** The context handle. */
816 HCRYPTPROV hProv;
817 } aCryptCtxs[4];
818 /** Number of reusable crypt conexts in aCryptCtxs. */
819 KU32 cCryptCtxs;
820 #endif
821
822
641823 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
642 /** Standard output (and whatever else) line buffer. */
643 KWCONSOLEOUTPUTLINE StdOut;
644 /** Standard error line buffer. */
645 KWCONSOLEOUTPUTLINE StdErr;
824 /** The internal standard output handle. */
825 KWHANDLE HandleStdOut;
826 /** The internal standard error handle. */
827 KWHANDLE HandleStdErr;
828 /** Standard output (and whatever else) buffer. */
829 KWOUTPUTSTREAMBUF StdOut;
830 /** Standard error buffer. */
831 KWOUTPUTSTREAMBUF StdErr;
646832 /** Combined buffer of completed lines. */
647833 KWCONSOLEOUTPUT Combined;
648834 #endif
691877 /** The module currently occupying g_abDefLdBuf. */
692878 static PKWMODULE g_pModInLdBuf = NULL;
693879
880 /** The module that previuosly occupied g_abDefLdBuf. */
881 static PKWMODULE g_pModPrevInLdBuf = NULL;
882
694883 /** Module hash table. */
695884 static PKWMODULE g_apModules[127];
696885
707896 static PKFSCACHE g_pFsCache;
708897 /** The current directory (referenced). */
709898 static PKFSOBJ g_pCurDirObj = NULL;
899 #ifdef KBUILD_OS_WINDOWS
900 /** The windows system32 directory (referenced). */
901 static PKFSDIR g_pWinSys32 = NULL;
902 #endif
710903
711904 /** Verbosity level. */
712905 static int g_cVerbose = 2;
713906
714907 /** Whether we should restart the worker. */
715908 static KBOOL g_fRestart = K_FALSE;
909
910 /** Whether control-C/SIGINT or Control-Break/SIGBREAK have been seen. */
911 static KBOOL volatile g_fCtrlC = K_FALSE;
716912
717913 /* Further down. */
718914 extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[];
721917 extern KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[];
722918 extern KU32 const g_cSandboxNativeReplacements;
723919
920 extern KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[];
921 extern KU32 const g_cSandboxGetProcReplacements;
922
923
724924 /** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should
725 * cover the default executable link address of 0x400000. */
726 #pragma section("DefLdBuf", write, execute, read)
727 __declspec(allocate("DefLdBuf"))
925 * cover the default executable link address of 0x400000.
926 * @remarks Early main() makes it read+write+executable. Attempts as having
927 * it as a separate section failed because the linker insists on
928 * writing out every zero in the uninitialized section, resulting in
929 * really big binaries. */
930 __declspec(align(0x1000))
728931 static KU8 g_abDefLdBuf[16*1024*1024];
729932
933 #ifdef WITH_LOG_FILE
934 /** Log file handle. */
935 static HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
936 #endif
937
938
939 #ifdef WITH_FIXED_VIRTUAL_ALLOCS
940 /** Virtual address space reserved for CL.EXE heap manager.
941 *
942 * Visual C++ 2010 reserves a 78MB chunk of memory from cl.exe at a fixed
943 * address. It's among other things used for precompiled headers, which
944 * seemingly have addresses hardcoded into them and won't work if mapped
945 * elsewhere. Thus, we have to make sure the area is available when cl.exe asks
946 * for it. (The /Zm option may affect this allocation.)
947 */
948 static struct
949 {
950 /** The memory address we need. */
951 KUPTR const uFixed;
952 /** How much we need to fix. */
953 KSIZE const cbFixed;
954 /** What we actually got, NULL if given back. */
955 void *pvReserved;
956 /** Whether it is in use or not. */
957 KBOOL fInUse;
958 } g_aFixedVirtualAllocs[] =
959 {
960 # if K_ARCH == K_ARCH_X86_32
961 /* Visual C++ 2010 reserves 0x04b00000 by default, and Visual C++ 2015 reserves
962 0x05300000. We get 0x0f000000 to handle large precompiled header files. */
963 { KUPTR_C( 0x11000000), KSIZE_C( 0x0f000000), NULL },
964 # else
965 { KUPTR_C(0x000006BB00000000), KSIZE_C(0x000000002EE00000), NULL },
966 # endif
967 };
968 #endif
969
970
971 #ifdef WITH_HISTORY
972 /** The job history. */
973 static char *g_apszHistory[32];
974 /** Index of the next history entry. */
975 static unsigned g_iHistoryNext = 0;
976 #endif
977
978
979 /** Number of jobs executed. */
980 static KU32 g_cJobs;
981 /** Number of tools. */
982 static KU32 g_cTools;
983 /** Number of modules. */
984 static KU32 g_cModules;
985 /** Number of non-native modules. */
986 static KU32 g_cNonNativeModules;
987 /** Number of read-cached files. */
988 static KU32 g_cReadCachedFiles;
989 /** Total size of read-cached files. */
990 static KSIZE g_cbReadCachedFiles;
991
992 /** Total number of ReadFile calls. */
993 static KSIZE g_cReadFileCalls;
994 /** Total bytes read via ReadFile. */
995 static KSIZE g_cbReadFileTotal;
996 /** Total number of read from read-cached files. */
997 static KSIZE g_cReadFileFromReadCached;
998 /** Total bytes read from read-cached files. */
999 static KSIZE g_cbReadFileFromReadCached;
1000 /** Total number of read from in-memory temporary files. */
1001 static KSIZE g_cReadFileFromInMemTemp;
1002 /** Total bytes read from in-memory temporary files. */
1003 static KSIZE g_cbReadFileFromInMemTemp;
1004
1005 /** Total number of WriteFile calls. */
1006 static KSIZE g_cWriteFileCalls;
1007 /** Total bytes written via WriteFile. */
1008 static KSIZE g_cbWriteFileTotal;
1009 /** Total number of written to from in-memory temporary files. */
1010 static KSIZE g_cWriteFileToInMemTemp;
1011 /** Total bytes written to in-memory temporary files. */
1012 static KSIZE g_cbWriteFileToInMemTemp;
7301013
7311014
7321015 /*********************************************************************************************************************************
7341017 *********************************************************************************************************************************/
7351018 static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback;
7361019 static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
737 static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle);
1020 static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle);
7381021 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
739 static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite);
1022 static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite);
7401023 #endif
1024
7411025
7421026
7431027
7511035 if (g_cVerbose >= 2)
7521036 {
7531037 DWORD const dwSavedErr = GetLastError();
754
1038 #ifdef WITH_LOG_FILE
1039 DWORD dwIgnored;
1040 char szTmp[2048];
1041 int cchPrefix = _snprintf(szTmp, sizeof(szTmp), "%x:%x: ", GetCurrentProcessId(), GetCurrentThreadId());
1042 int cch = vsnprintf(&szTmp[cchPrefix], sizeof(szTmp) - cchPrefix, pszFormat, va);
1043 if (cch < (int)sizeof(szTmp) - 1 - cchPrefix)
1044 cch += cchPrefix;
1045 else
1046 {
1047 cch = sizeof(szTmp) - 1;
1048 szTmp[cch] = '\0';
1049 }
1050
1051 if (g_hLogFile == INVALID_HANDLE_VALUE)
1052 {
1053 wchar_t wszFilename[128];
1054 _snwprintf(wszFilename, K_ELEMENTS(wszFilename), L"kWorker-%x-%x.log", GetTickCount(), GetCurrentProcessId());
1055 g_hLogFile = CreateFileW(wszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL /*pSecAttrs*/, CREATE_ALWAYS,
1056 FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
1057 }
1058
1059 WriteFile(g_hLogFile, szTmp, cch, &dwIgnored, NULL /*pOverlapped*/);
1060 #else
7551061 fprintf(stderr, "debug: ");
7561062 vfprintf(stderr, pszFormat, va);
1063 #endif
7571064
7581065 SetLastError(dwSavedErr);
7591066 }
13251632
13261633 if (!pMod->fNative)
13271634 {
1328 kHlpPageFree(pMod->u.Manual.pvCopy, pMod->cbImage);
1329 kHlpPageFree(pMod->u.Manual.pvLoad, pMod->cbImage);
1635 kHlpPageFree(pMod->u.Manual.pbCopy, pMod->cbImage);
1636 kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage);
13301637 }
13311638
13321639 kHlpFree(pMod);
15461853
15471854 KW_LOG(("New module: %p LB %#010x %s (native)\n",
15481855 (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath));
1856 g_cModules++;
15491857 return kwLdrModuleLink(pMod);
15501858 }
15511859 return NULL;
15781886 kLdrModClose(pLdrMod);
15791887 }
15801888 return NULL;
1889 }
1890
1891
1892 /**
1893 * Sets up the quick zero & copy tables for the non-native module.
1894 *
1895 * This is a worker for kwLdrModuleCreateNonNative.
1896 *
1897 * @param pMod The module.
1898 */
1899 static void kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(PKWMODULE pMod)
1900 {
1901 PCKLDRSEG paSegs = pMod->pLdrMod->aSegments;
1902 KU32 cSegs = pMod->pLdrMod->cSegments;
1903 KU32 iSeg;
1904
1905 KWLDR_LOG(("Setting up quick zero & copy for %s:\n", pMod->pszPath));
1906 pMod->u.Manual.cQuickCopyChunks = 0;
1907 pMod->u.Manual.cQuickZeroChunks = 0;
1908
1909 for (iSeg = 0; iSeg < cSegs; iSeg++)
1910 switch (paSegs[iSeg].enmProt)
1911 {
1912 case KPROT_READWRITE:
1913 case KPROT_WRITECOPY:
1914 case KPROT_EXECUTE_READWRITE:
1915 case KPROT_EXECUTE_WRITECOPY:
1916 if (paSegs[iSeg].cbMapped)
1917 {
1918 KU32 iChunk = pMod->u.Manual.cQuickCopyChunks;
1919 if (iChunk < K_ELEMENTS(pMod->u.Manual.aQuickCopyChunks))
1920 {
1921 /*
1922 * Check for trailing zero words.
1923 */
1924 KSIZE cbTrailingZeros;
1925 if ( paSegs[iSeg].cbMapped >= 64 * 2 * sizeof(KSIZE)
1926 && (paSegs[iSeg].cbMapped & 7) == 0
1927 && pMod->u.Manual.cQuickZeroChunks < K_ELEMENTS(pMod->u.Manual.aQuickZeroChunks) )
1928 {
1929 KSIZE const *pauNatural = (KSIZE const *)&pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA];
1930 KSIZE cNatural = paSegs[iSeg].cbMapped / sizeof(KSIZE);
1931 KSIZE idxFirstZero = cNatural;
1932 while (idxFirstZero > 0)
1933 if (pauNatural[--idxFirstZero] == 0)
1934 { /* likely */ }
1935 else
1936 {
1937 idxFirstZero++;
1938 break;
1939 }
1940 cbTrailingZeros = (cNatural - idxFirstZero) * sizeof(KSIZE);
1941 if (cbTrailingZeros < 128)
1942 cbTrailingZeros = 0;
1943 }
1944 else
1945 cbTrailingZeros = 0;
1946
1947 /*
1948 * Add quick copy entry.
1949 */
1950 if (cbTrailingZeros < paSegs[iSeg].cbMapped)
1951 {
1952 pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst = &pMod->u.Manual.pbLoad[(KSIZE)paSegs[iSeg].RVA];
1953 pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc = &pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA];
1954 pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy = paSegs[iSeg].cbMapped - cbTrailingZeros;
1955 pMod->u.Manual.cQuickCopyChunks = iChunk + 1;
1956 KWLDR_LOG(("aQuickCopyChunks[%u]: %#p LB %#" KSIZE_PRI " <- %p (%*.*s)\n", iChunk,
1957 pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst,
1958 pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy,
1959 pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc,
1960 paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName));
1961 }
1962
1963 /*
1964 * Add quick zero entry.
1965 */
1966 if (cbTrailingZeros)
1967 {
1968 KU32 iZero = pMod->u.Manual.cQuickZeroChunks;
1969 pMod->u.Manual.aQuickZeroChunks[iZero].pbDst = pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst
1970 + pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy;
1971 pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero = cbTrailingZeros;
1972 pMod->u.Manual.cQuickZeroChunks = iZero + 1;
1973 KWLDR_LOG(("aQuickZeroChunks[%u]: %#p LB %#" KSIZE_PRI " <- zero (%*.*s)\n", iZero,
1974 pMod->u.Manual.aQuickZeroChunks[iZero].pbDst,
1975 pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero,
1976 paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName));
1977 }
1978 }
1979 else
1980 {
1981 /*
1982 * We're out of quick copy table entries, so just copy the whole darn thing.
1983 * We cannot 104% guarantee that the segments are in mapping order, so this is simpler.
1984 */
1985 kHlpAssertFailed();
1986 pMod->u.Manual.aQuickCopyChunks[0].pbDst = pMod->u.Manual.pbLoad;
1987 pMod->u.Manual.aQuickCopyChunks[0].pbSrc = pMod->u.Manual.pbCopy;
1988 pMod->u.Manual.aQuickCopyChunks[0].cbToCopy = pMod->cbImage;
1989 pMod->u.Manual.cQuickCopyChunks = 1;
1990 KWLDR_LOG(("Quick copy not possible!\n"));
1991 return;
1992 }
1993 }
1994 break;
1995
1996 default:
1997 break;
1998 }
15811999 }
15822000
15832001
16462064 pMod->fNative = K_FALSE;
16472065 pMod->pLdrMod = pLdrMod;
16482066 pMod->u.Manual.cImpMods = (KU32)cImports;
1649 pMod->u.Manual.fUseLdBuf = K_FALSE;
16502067 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
16512068 pMod->u.Manual.fRegisteredFunctionTable = K_FALSE;
16522069 #endif
2070 pMod->u.Manual.fUseLdBuf = K_FALSE;
2071 pMod->u.Manual.fCanDoQuick = K_FALSE;
2072 pMod->u.Manual.cQuickZeroChunks = 0;
2073 pMod->u.Manual.cQuickCopyChunks = 0;
16532074 pMod->pszPath = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath);
16542075 pMod->pwszPath = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
16552076 kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
16592080 */
16602081 fFixed = pLdrMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
16612082 || pLdrMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1662 pMod->u.Manual.pvLoad = fFixed ? (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL;
2083 pMod->u.Manual.pbLoad = fFixed ? (KU8 *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL;
16632084 pMod->cbImage = (KSIZE)kLdrModSize(pLdrMod);
16642085 if ( !fFixed
16652086 || pLdrMod->enmType != KLDRTYPE_EXECUTABLE_FIXED /* only allow fixed executables */
1666 || (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf)
1667 || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf < pMod->cbImage)
1668 rc = kHlpPageAlloc(&pMod->u.Manual.pvLoad, pMod->cbImage, KPROT_EXECUTE_READWRITE, fFixed);
2087 || (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf)
2088 || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf < pMod->cbImage)
2089 rc = kHlpPageAlloc((void **)&pMod->u.Manual.pbLoad, pMod->cbImage, KPROT_EXECUTE_READWRITE, fFixed);
16692090 else
16702091 pMod->u.Manual.fUseLdBuf = K_TRUE;
16712092 if (rc == 0)
16722093 {
1673 rc = kHlpPageAlloc(&pMod->u.Manual.pvCopy, pMod->cbImage, KPROT_READWRITE, K_FALSE);
2094 rc = kHlpPageAlloc(&pMod->u.Manual.pbCopy, pMod->cbImage, KPROT_READWRITE, K_FALSE);
16742095 if (rc == 0)
16752096 {
1676
16772097 KI32 iImp;
16782098
16792099 /*
16802100 * Link the module (unless it's an executable image) and process the imports.
16812101 */
1682 pMod->hOurMod = (HMODULE)pMod->u.Manual.pvLoad;
2102 pMod->hOurMod = (HMODULE)pMod->u.Manual.pbLoad;
16832103 if (!fExe)
16842104 kwLdrModuleLink(pMod);
16852105 KW_LOG(("New module: %p LB %#010x %s (kLdr)\n",
1686 pMod->u.Manual.pvLoad, pMod->cbImage, pMod->pszPath));
1687 kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pvLoad);
2106 pMod->u.Manual.pbLoad, pMod->cbImage, pMod->pszPath));
2107 kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad);
16882108
16892109 for (iImp = 0; iImp < cImports; iImp++)
16902110 {
17012121
17022122 if (rc == 0)
17032123 {
1704 rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pvCopy, (KUPTR)pMod->u.Manual.pvLoad,
2124 rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pbCopy, (KUPTR)pMod->u.Manual.pbLoad,
17052125 kwLdrModuleGetImportCallback, pMod);
17062126 if (rc == 0)
17072127 {
17102130 * Find the function table. No validation here because the
17112131 * loader did that already, right...
17122132 */
1713 KU8 *pbImg = (KU8 *)pMod->u.Manual.pvCopy;
2133 KU8 *pbImg = (KU8 *)pMod->u.Manual.pbCopy;
17142134 IMAGE_NT_HEADERS const *pNtHdrs;
17152135 IMAGE_DATA_DIRECTORY const *pXcptDir;
17162136 if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE)
17332153 }
17342154 #endif
17352155
2156 kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(pMod);
2157
17362158 /*
17372159 * Final finish.
17382160 */
1739 pMod->u.Manual.pvBits = pMod->u.Manual.pvCopy;
2161 pMod->u.Manual.pvBits = pMod->u.Manual.pbCopy;
17402162 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
2163 g_cModules++;
2164 g_cNonNativeModules++;
17412165 return pMod;
17422166 }
17432167 }
17462170 return NULL;
17472171 }
17482172
1749 kHlpPageFree(pMod->u.Manual.pvLoad, pMod->cbImage);
2173 kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage);
17502174 kwErrPrintf("Failed to allocate %#x bytes\n", pMod->cbImage);
17512175 }
17522176 else if (fFixed)
17802204 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
17812205 puValue, pfKind);
17822206 else
1783 rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pvLoad,
2207 rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pbLoad,
17842208 iSymbol, pchSymbol, cchSymbol, pszVersion,
17852209 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
17862210 puValue, pfKind);
18212245 static int kwLdrModuleQueryMainEntrypoint(PKWMODULE pMod, KUPTR *puAddrMain)
18222246 {
18232247 KLDRADDR uLdrAddrMain;
1824 int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod, pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pvLoad, &uLdrAddrMain);
2248 int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod, pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pbLoad, &uLdrAddrMain);
18252249 if (rc == 0)
18262250 {
18272251 *puAddrMain = (KUPTR)uLdrAddrMain;
18492273
18502274
18512275 /**
2276 * Lazily initializes the g_pWinSys32 variable.
2277 */
2278 static PKFSDIR kwLdrResolveWinSys32(void)
2279 {
2280 KFSLOOKUPERROR enmError;
2281 PKFSDIR pWinSys32;
2282
2283 /* Get the path first. */
2284 char szSystem32[MAX_PATH];
2285 if (GetSystemDirectoryA(szSystem32, sizeof(szSystem32)) >= sizeof(szSystem32))
2286 {
2287 kwErrPrintf("GetSystemDirectory failed: %u\n", GetLastError());
2288 strcpy(szSystem32, "C:\\Windows\\System32");
2289 }
2290
2291 /* Look it up and verify it. */
2292 pWinSys32 = (PKFSDIR)kFsCacheLookupA(g_pFsCache, szSystem32, &enmError);
2293 if (pWinSys32)
2294 {
2295 if (pWinSys32->Obj.bObjType == KFSOBJ_TYPE_DIR)
2296 {
2297 g_pWinSys32 = pWinSys32;
2298 return pWinSys32;
2299 }
2300
2301 kwErrPrintf("System directory '%s' isn't of 'DIR' type: %u\n", szSystem32, g_pWinSys32->Obj.bObjType);
2302 }
2303 else
2304 kwErrPrintf("Failed to lookup system directory '%s': %u\n", szSystem32, enmError);
2305 return NULL;
2306 }
2307
2308
2309 /**
18522310 * Whether we can load this DLL natively or not.
18532311 *
18542312 * @returns K_TRUE/K_FALSE.
18552313 * @param pszFilename The filename (no path).
18562314 * @param enmLocation The location.
1857 */
1858 static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation)
2315 * @param pszFullPath The full filename and path.
2316 */
2317 static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation, const char *pszFullPath)
18592318 {
18602319 if (enmLocation == KWLOCATION_SYSTEM32)
18612320 return K_TRUE;
18622321 if (enmLocation == KWLOCATION_UNKNOWN_NATIVE)
18632322 return K_TRUE;
2323
2324 /* If the location is unknown, we must check if it's some dynamic loading
2325 of a SYSTEM32 DLL with a full path. We do not want to load these ourselves! */
2326 if (enmLocation == KWLOCATION_UNKNOWN)
2327 {
2328 PKFSDIR pWinSys32 = g_pWinSys32;
2329 if (!pWinSys32)
2330 pWinSys32 = kwLdrResolveWinSys32();
2331 if (pWinSys32)
2332 {
2333 KFSLOOKUPERROR enmError;
2334 PKFSOBJ pFsObj = kFsCacheLookupA(g_pFsCache, pszFullPath, &enmError);
2335 if (pFsObj)
2336 {
2337 KBOOL fInWinSys32 = pFsObj->pParent == pWinSys32;
2338 kFsCacheObjRelease(g_pFsCache, pFsObj);
2339 if (fInWinSys32)
2340 return K_TRUE;
2341 }
2342 }
2343 }
2344
18642345 return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0
18652346 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0
18662347 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0;
19532434 * Not in the hash table, so we have to load it from scratch.
19542435 */
19552436 pszName = kHlpGetFilename(szNormPath);
1956 if (kwLdrModuleCanLoadNatively(pszName, enmLocation))
2437 if (kwLdrModuleCanLoadNatively(pszName, enmLocation, szNormPath))
19572438 pMod = kwLdrModuleCreateNative(szNormPath, uHashPath,
19582439 kwLdrModuleShouldDoNativeReplacements(pszName, enmLocation));
19592440 else
20532534 int rc = 0;
20542535 if (!pMod->fNative)
20552536 {
2056 /* Need to copy bits? */
2537 /*
2538 * Need to copy bits?
2539 */
20572540 if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_BITS)
20582541 {
20592542 if (pMod->u.Manual.fUseLdBuf)
20652548 kHlpAssert(fRc); K_NOREF(fRc);
20662549 }
20672550 #endif
2551 g_pModPrevInLdBuf = g_pModInLdBuf;
20682552 g_pModInLdBuf = pMod;
20692553 }
20702554
2071 kHlpMemCopy(pMod->u.Manual.pvLoad, pMod->u.Manual.pvCopy, pMod->cbImage);
2555 /* Do quick zeroing and copying when we can. */
2556 pMod->u.Manual.fCanDoQuick = K_FALSE;
2557 if ( pMod->u.Manual.fCanDoQuick
2558 && ( !pMod->u.Manual.fUseLdBuf
2559 || g_pModPrevInLdBuf == pMod))
2560 {
2561 /* Zero first. */
2562 kHlpAssert(pMod->u.Manual.cQuickZeroChunks <= 3);
2563 switch (pMod->u.Manual.cQuickZeroChunks)
2564 {
2565 case 3: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[2].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[2].cbToZero);
2566 case 2: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[1].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[1].cbToZero);
2567 case 1: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[0].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[0].cbToZero);
2568 case 0: break;
2569 }
2570
2571 /* Then copy. */
2572 kHlpAssert(pMod->u.Manual.cQuickCopyChunks > 0);
2573 kHlpAssert(pMod->u.Manual.cQuickCopyChunks <= 3);
2574 switch (pMod->u.Manual.cQuickCopyChunks)
2575 {
2576 case 3: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[2].pbDst, pMod->u.Manual.aQuickCopyChunks[2].pbSrc,
2577 pMod->u.Manual.aQuickCopyChunks[2].cbToCopy);
2578 case 2: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[1].pbDst, pMod->u.Manual.aQuickCopyChunks[1].pbSrc,
2579 pMod->u.Manual.aQuickCopyChunks[1].cbToCopy);
2580 case 1: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[0].pbDst, pMod->u.Manual.aQuickCopyChunks[0].pbSrc,
2581 pMod->u.Manual.aQuickCopyChunks[0].cbToCopy);
2582 case 0: break;
2583 }
2584 }
2585 /* Must copy the whole image. */
2586 else
2587 {
2588 kHlpMemCopy(pMod->u.Manual.pbLoad, pMod->u.Manual.pbCopy, pMod->cbImage);
2589 pMod->u.Manual.fCanDoQuick = K_TRUE;
2590 }
20722591 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_INIT;
20732592 }
20742593
20752594 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
2076 /* Need to register function table? */
2595 /*
2596 * Need to register function table?
2597 */
20772598 if ( !pMod->u.Manual.fRegisteredFunctionTable
20782599 && pMod->u.Manual.cFunctions > 0)
20792600 {
20802601 pMod->u.Manual.fRegisteredFunctionTable = RtlAddFunctionTable(pMod->u.Manual.paFunctions,
20812602 pMod->u.Manual.cFunctions,
2082 (KUPTR)pMod->u.Manual.pvLoad) != FALSE;
2603 (KUPTR)pMod->u.Manual.pbLoad) != FALSE;
20832604 kHlpAssert(pMod->u.Manual.fRegisteredFunctionTable);
20842605 }
20852606 #endif
20862607
20872608 if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT)
20882609 {
2089 /* Must do imports first, but mark our module as being initialized to avoid
2090 endless recursion should there be a dependency loop. */
2610 /*
2611 * Must do imports first, but mark our module as being initialized to avoid
2612 * endless recursion should there be a dependency loop.
2613 */
20912614 KSIZE iImp;
20922615 pMod->u.Manual.enmState = KWMODSTATE_BEING_INITED;
20932616
20982621 return rc;
20992622 }
21002623
2101 rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pvLoad, (KUPTR)pMod->u.Manual.pvLoad);
2624 rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod);
21022625 if (rc == 0)
21032626 pMod->u.Manual.enmState = KWMODSTATE_READY;
21042627 else
23492872 pTool->enmType = KWTOOLTYPE_EXEC;
23502873
23512874 kFsCacheObjRelease(g_pFsCache, pToolFsObj);
2875 g_cTools++;
23522876 return pTool;
23532877 }
23542878 kFsCacheObjRelease(g_pFsCache, pToolFsObj);
24002924 *
24012925 */
24022926
2927
2928 /**
2929 * This is for kDep.
2930 */
2931 int kwFsPathExists(const char *pszPath)
2932 {
2933 BirdTimeSpec_T TsIgnored;
2934 KFSLOOKUPERROR enmError;
2935 PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszPath, &enmError);
2936 if (pFsObj)
2937 {
2938 kFsCacheObjRelease(g_pFsCache, pFsObj);
2939 return 1;
2940 }
2941 return birdStatModTimeOnly(pszPath, &TsIgnored, 1) == 0;
2942 }
2943
2944
2945 /* duplicated in dir-nt-bird.c */
2946 void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
2947 {
2948 KFSLOOKUPERROR enmError;
2949 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
2950 if (pPathObj)
2951 {
2952 KSIZE off = pPathObj->cchParent;
2953 if (off > 0)
2954 {
2955 KSIZE offEnd = off + pPathObj->cchName;
2956 if (offEnd < cbFull)
2957 {
2958 PKFSDIR pAncestor;
2959
2960 pszFull[off + pPathObj->cchName] = '\0';
2961 memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName);
2962
2963 for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
2964 {
2965 kHlpAssert(off > 1);
2966 kHlpAssert(pAncestor != NULL);
2967 kHlpAssert(pAncestor->Obj.cchName > 0);
2968 pszFull[--off] = '/';
2969 off -= pAncestor->Obj.cchName;
2970 kHlpAssert(pAncestor->Obj.cchParent == off);
2971 memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName);
2972 }
2973 kFsCacheObjRelease(g_pFsCache, pPathObj);
2974 return;
2975 }
2976 }
2977 else
2978 {
2979 if ((size_t)pPathObj->cchName + 1 < cbFull)
2980 {
2981 memcpy(pszFull, pPathObj->pszName, pPathObj->cchName);
2982 pszFull[pPathObj->cchName] = '/';
2983 pszFull[pPathObj->cchName + 1] = '\0';
2984
2985 kFsCacheObjRelease(g_pFsCache, pPathObj);
2986 return;
2987 }
2988 }
2989
2990 /* do fallback. */
2991 kHlpAssertFailed();
2992 kFsCacheObjRelease(g_pFsCache, pPathObj);
2993 }
2994
2995 nt_fullpath(pszPath, pszFull, cbFull);
2996 }
24032997
24042998
24052999 /**
26363230 /** CRT - _onexit */
26373231 static _onexit_t __cdecl kwSandbox_msvcrt__onexit(_onexit_t pfnFunc)
26383232 {
2639 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
3233 //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
26403234 {
26413235 PKWEXITCALLACK pCallback;
26423236 KW_LOG(("_onexit(%p)\n", pfnFunc));
26613255 /** CRT - atexit */
26623256 static int __cdecl kwSandbox_msvcrt_atexit(int (__cdecl *pfnFunc)(void))
26633257 {
2664 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
3258 //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
26653259 {
26663260 PKWEXITCALLACK pCallback;
26673261 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
30243618 KSIZE cNew = cOld + 256;
30253619 while (cNew < cMin)
30263620 cNew += 256;
3027
30283621
30293622 pvNew = kHlpRealloc(pSandbox->environ, cNew * sizeof(pSandbox->environ[0]));
30303623 if (pvNew)
39674560 }
39684561
39694562
4563 #ifndef NDEBUG
4564 /*
4565 * This wraps up to three InvokeCompilerPassW functions and dumps their arguments to the log.
4566 */
4567 # if K_ARCH == K_ARCH_X86_32
4568 static char g_szInvokeCompilePassW[] = "_InvokeCompilerPassW@16";
4569 # else
4570 static char g_szInvokeCompilePassW[] = "InvokeCompilerPassW";
4571 # endif
4572 typedef KIPTR __stdcall FNINVOKECOMPILERPASSW(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance);
4573 typedef FNINVOKECOMPILERPASSW *PFNINVOKECOMPILERPASSW;
4574 typedef struct KWCXINTERCEPTORENTRY
4575 {
4576 PFNINVOKECOMPILERPASSW pfnOrg;
4577 PKWMODULE pModule;
4578 PFNINVOKECOMPILERPASSW pfnWrap;
4579 } KWCXINTERCEPTORENTRY;
4580
4581 static KIPTR kwSandbox_Cx_InvokeCompilerPassW_Common(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance,
4582 KWCXINTERCEPTORENTRY *pEntry)
4583 {
4584 int i;
4585 KIPTR rcExit;
4586 KW_LOG(("%s!InvokeCompilerPassW(%d, %p, %#x, %p)\n",
4587 &pEntry->pModule->pszPath[pEntry->pModule->offFilename], cArgs, papwszArgs, fFlags, phCluiInstance));
4588 for (i = 0; i < cArgs; i++)
4589 KW_LOG((" papwszArgs[%u]='%ls'\n", i, papwszArgs[i]));
4590
4591 rcExit = pEntry->pfnOrg(cArgs, papwszArgs, fFlags, phCluiInstance);
4592
4593 KW_LOG(("%s!InvokeCompilerPassW returns %d\n", &pEntry->pModule->pszPath[pEntry->pModule->offFilename], rcExit));
4594 return rcExit;
4595 }
4596
4597 static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_0;
4598 static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_1;
4599 static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_2;
4600
4601 static KWCXINTERCEPTORENTRY g_aCxInterceptorEntries[] =
4602 {
4603 { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_0 },
4604 { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_1 },
4605 { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_2 },
4606 };
4607
4608 static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_0(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance)
4609 {
4610 return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[0]);
4611 }
4612
4613 static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_1(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance)
4614 {
4615 return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[1]);
4616 }
4617
4618 static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_2(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance)
4619 {
4620 return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[2]);
4621 }
4622
4623 #endif /* !NDEBUG */
4624
4625
39704626 /** Kernel32 - GetProcAddress() */
39714627 static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc)
39724628 {
39834639 KLDRADDR uValue;
39844640 int rc = kLdrModQuerySymbol(pMod->pLdrMod,
39854641 pMod->fNative ? NULL : pMod->u.Manual.pvBits,
3986 pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pvLoad,
4642 pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pbLoad,
39874643 KU32_MAX /*iSymbol*/,
39884644 pszProc,
39894645 kHlpStrLen(pszProc),
39934649 NULL /*pfKind*/);
39944650 if (rc == 0)
39954651 {
3996 static int s_cDbgGets = 0;
3997 s_cDbgGets++;
3998 KW_LOG(("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets));
4652 //static int s_cDbgGets = 0;
4653 KU32 cchProc = (KU32)kHlpStrLen(pszProc);
4654 KU32 i = g_cSandboxGetProcReplacements;
4655 while (i-- > 0)
4656 if ( g_aSandboxGetProcReplacements[i].cchFunction == cchProc
4657 && kHlpMemComp(g_aSandboxGetProcReplacements[i].pszFunction, pszProc, cchProc) == 0)
4658 {
4659 if ( !g_aSandboxGetProcReplacements[i].pszModule
4660 || kHlpStrICompAscii(g_aSandboxGetProcReplacements[i].pszModule, &pMod->pszPath[pMod->offFilename]) == 0)
4661 {
4662 if ( !g_aSandboxGetProcReplacements[i].fOnlyExe
4663 || (KUPTR)_ReturnAddress() - (KUPTR)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod
4664 < g_Sandbox.pTool->u.Sandboxed.pExe->cbImage)
4665 {
4666 uValue = g_aSandboxGetProcReplacements[i].pfnReplacement;
4667 KW_LOG(("GetProcAddress(%s, %s) -> %p replaced\n", pMod->pszPath, pszProc, (KUPTR)uValue));
4668 }
4669 kwLdrModuleRelease(pMod);
4670 return (FARPROC)(KUPTR)uValue;
4671 }
4672 }
4673
4674 #ifndef NDEBUG
4675 /* Intercept the compiler pass method, dumping arguments. */
4676 if (kHlpStrComp(pszProc, g_szInvokeCompilePassW) == 0)
4677 {
4678 KU32 i;
4679 for (i = 0; i < K_ELEMENTS(g_aCxInterceptorEntries); i++)
4680 if ((KUPTR)g_aCxInterceptorEntries[i].pfnOrg == uValue)
4681 {
4682 uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap;
4683 KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW\n"));
4684 break;
4685 }
4686 if (i >= K_ELEMENTS(g_aCxInterceptorEntries))
4687 while (i-- > 0)
4688 if (g_aCxInterceptorEntries[i].pfnOrg == NULL)
4689 {
4690 g_aCxInterceptorEntries[i].pfnOrg = (PFNINVOKECOMPILERPASSW)(KUPTR)uValue;
4691 g_aCxInterceptorEntries[i].pModule = pMod;
4692 uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap;
4693 KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW (new)\n"));
4694 break;
4695 }
4696 }
4697 #endif
4698 KW_LOG(("GetProcAddress(%s, %s) -> %p\n", pMod->pszPath, pszProc, (KUPTR)uValue));
39994699 kwLdrModuleRelease(pMod);
4700 //s_cDbgGets++;
40004701 //if (s_cGets >= 3)
40014702 // return (FARPROC)kwSandbox_BreakIntoDebugger;
40024703 return (FARPROC)(KUPTR)uValue;
42434944 if (pHandle)
42444945 {
42454946 pHandle->enmType = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING;
4947 pHandle->cRefs = 1;
42464948 pHandle->offFile = 0;
42474949 pHandle->hHandle = hFile;
42484950 pHandle->dwDesiredAccess = dwDesiredAccess;
42494951 pHandle->u.pTempFile = pTempFile;
4250 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
4952 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, hFile))
42514953 {
42524954 pTempFile->cActiveHandles++;
42534955 kHlpAssert(pTempFile->cActiveHandles >= 1);
43855087
43865088 #endif /* WITH_TEMP_MEMORY_FILES */
43875089
5090 /**
5091 * Worker for kwFsIsCacheableExtensionA and kwFsIsCacheableExtensionW
5092 *
5093 * @returns K_TRUE if cacheable, K_FALSE if not.
5094 * @param wcFirst The first extension character.
5095 * @param wcSecond The second extension character.
5096 * @param wcThird The third extension character.
5097 * @param fAttrQuery Set if it's for an attribute query, clear if for
5098 * file creation.
5099 */
5100 static KBOOL kwFsIsCacheableExtensionCommon(wchar_t wcFirst, wchar_t wcSecond, wchar_t wcThird, KBOOL fAttrQuery)
5101 {
5102 /* C++ header without an extension or a directory. */
5103 if (wcFirst == '\0')
5104 {
5105 /** @todo exclude temporary files... */
5106 return K_TRUE;
5107 }
5108
5109 /* C Header: .h */
5110 if (wcFirst == 'h' || wcFirst == 'H')
5111 {
5112 if (wcSecond == '\0')
5113 return K_TRUE;
5114
5115 /* C++ Header: .hpp, .hxx */
5116 if ( (wcSecond == 'p' || wcSecond == 'P')
5117 && (wcThird == 'p' || wcThird == 'P'))
5118 return K_TRUE;
5119 if ( (wcSecond == 'x' || wcSecond == 'X')
5120 && (wcThird == 'x' || wcThird == 'X'))
5121 return K_TRUE;
5122 }
5123 /* Misc starting with i. */
5124 else if (wcFirst == 'i' || wcFirst == 'I')
5125 {
5126 if (wcSecond != '\0')
5127 {
5128 if (wcSecond == 'n' || wcSecond == 'N')
5129 {
5130 /* C++ inline header: .inl */
5131 if (wcThird == 'l' || wcThird == 'L')
5132 return K_TRUE;
5133
5134 /* Assembly include file: .inc */
5135 if (wcThird == 'c' || wcThird == 'C')
5136 return K_TRUE;
5137 }
5138 }
5139 }
5140 /* Assembly header: .mac */
5141 else if (wcFirst == 'm' || wcFirst == 'M')
5142 {
5143 if (wcSecond == 'a' || wcSecond == 'A')
5144 {
5145 if (wcThird == 'c' || wcThird == 'C')
5146 return K_TRUE;
5147 }
5148 }
5149 #ifdef WITH_PCH_CACHING
5150 /* Precompiled header: .pch */
5151 else if (wcFirst == 'p' || wcFirst == 'P')
5152 {
5153 if (wcSecond == 'c' || wcSecond == 'C')
5154 {
5155 if (wcThird == 'h' || wcThird == 'H')
5156 return !g_Sandbox.fNoPchCaching;
5157 }
5158 }
5159 #endif
5160 #if 0 /* Experimental - need to flush these afterwards as they're highly unlikely to be used after the link is done. */
5161 /* Linker - Object file: .obj */
5162 if ((wcFirst == 'o' || wcFirst == 'O') && g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
5163 {
5164 if (wcSecond == 'b' || wcSecond == 'B')
5165 {
5166 if (wcThird == 'j' || wcThird == 'J')
5167 return K_TRUE;
5168 }
5169 }
5170 #endif
5171 else if (fAttrQuery)
5172 {
5173 /* Dynamic link library: .dll */
5174 if (wcFirst == 'd' || wcFirst == 'D')
5175 {
5176 if (wcSecond == 'l' || wcSecond == 'L')
5177 {
5178 if (wcThird == 'l' || wcThird == 'L')
5179 return K_TRUE;
5180 }
5181 }
5182 /* Executable file: .exe */
5183 else if (wcFirst == 'e' || wcFirst == 'E')
5184 {
5185 if (wcSecond == 'x' || wcSecond == 'X')
5186 {
5187 if (wcThird == 'e' || wcThird == 'E')
5188 return K_TRUE;
5189 }
5190 }
5191 /* Response file: .rsp */
5192 else if (wcFirst == 'r' || wcFirst == 'R')
5193 {
5194 if (wcSecond == 's' || wcSecond == 'S')
5195 {
5196 if (wcThird == 'p' || wcThird == 'P')
5197 return !g_Sandbox.fNoPchCaching;
5198 }
5199 }
5200 /* Linker: */
5201 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
5202 {
5203 /* Object file: .obj */
5204 if (wcFirst == 'o' || wcFirst == 'O')
5205 {
5206 if (wcSecond == 'b' || wcSecond == 'B')
5207 {
5208 if (wcThird == 'j' || wcThird == 'J')
5209 return K_TRUE;
5210 }
5211 }
5212 /* Library file: .lib */
5213 else if (wcFirst == 'l' || wcFirst == 'L')
5214 {
5215 if (wcSecond == 'i' || wcSecond == 'I')
5216 {
5217 if (wcThird == 'b' || wcThird == 'B')
5218 return K_TRUE;
5219 }
5220 }
5221 /* Linker definition file: .def */
5222 else if (wcFirst == 'd' || wcFirst == 'D')
5223 {
5224 if (wcSecond == 'e' || wcSecond == 'E')
5225 {
5226 if (wcThird == 'f' || wcThird == 'F')
5227 return K_TRUE;
5228 }
5229 }
5230 }
5231 }
5232
5233 return K_FALSE;
5234 }
5235
43885236
43895237 /**
43905238 * Checks if the file extension indicates that the file/dir is something we
43955243 * @param fAttrQuery Set if it's for an attribute query, clear if for
43965244 * file creation.
43975245 */
4398 static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery)
4399 {
4400 char const chFirst = *pszExt;
4401
4402 /* C++ header without an extension or a directory. */
4403 if (chFirst == '\0')
4404 {
4405 /** @todo exclude temporary files... */
4406 return K_TRUE;
4407 }
4408
4409 /* C Header: .h */
4410 if (chFirst == 'h' || chFirst == 'H')
4411 {
4412 char chThird;
4413 char const chSecond = pszExt[1];
4414 if (chSecond == '\0')
4415 return K_TRUE;
4416 chThird = pszExt[2];
4417
4418 /* C++ Header: .hpp, .hxx */
4419 if ( (chSecond == 'p' || chSecond == 'P')
4420 && (chThird == 'p' || chThird == 'P')
4421 && pszExt[3] == '\0')
4422 return K_TRUE;
4423 if ( (chSecond == 'x' || chSecond == 'X')
4424 && (chThird == 'x' || chThird == 'X')
4425 && pszExt[3] == '\0')
4426 return K_TRUE;
4427 }
4428 /* Misc starting with i. */
4429 else if (chFirst == 'i' || chFirst == 'I')
4430 {
4431 char const chSecond = pszExt[1];
4432 if (chSecond != '\0')
4433 {
4434 if (chSecond == 'n' || chSecond == 'N')
4435 {
4436 char const chThird = pszExt[2];
4437
4438 /* C++ inline header: .inl */
4439 if ( (chThird == 'l' || chThird == 'L')
4440 && pszExt[3] == '\0')
4441 return K_TRUE;
4442
4443 /* Assembly include file: .inc */
4444 if ( (chThird == 'c' || chThird == 'C')
4445 && pszExt[3] == '\0')
4446 return K_TRUE;
4447 }
4448 }
4449 }
4450 /* Assembly header: .mac */
4451 else if (chFirst == 'm' || chFirst == 'M')
4452 {
4453 char const chSecond = pszExt[1];
4454 if (chSecond == 'a' || chSecond == 'A')
4455 {
4456 char const chThird = pszExt[2];
4457 if ( (chThird == 'c' || chThird == 'C')
4458 && pszExt[3] == '\0')
4459 return K_TRUE;
4460 }
4461 }
4462 else if (fAttrQuery)
4463 {
4464 /* Dynamic link library: .dll */
4465 if (chFirst == 'd' || chFirst == 'D')
4466 {
4467 char const chSecond = pszExt[1];
4468 if (chSecond == 'l' || chSecond == 'L')
4469 {
4470 char const chThird = pszExt[2];
4471 if (chThird == 'l' || chThird == 'L')
4472 return K_TRUE;
4473 }
4474 }
4475 /* Executable file: .exe */
4476 else if (chFirst == 'e' || chFirst == 'E')
4477 {
4478 char const chSecond = pszExt[1];
4479 if (chSecond == 'x' || chSecond == 'X')
4480 {
4481 char const chThird = pszExt[2];
4482 if (chThird == 'e' || chThird == 'e')
4483 return K_TRUE;
4484 }
4485 }
4486 }
4487
4488 return K_FALSE;
5246 static KBOOL kwFsIsCacheableExtensionA(const char *pszExt, KBOOL fAttrQuery)
5247 {
5248 wchar_t const wcFirst = *pszExt;
5249 if (wcFirst)
5250 {
5251 wchar_t const wcSecond = pszExt[1];
5252 if (wcSecond)
5253 {
5254 wchar_t const wcThird = pszExt[2];
5255 if (pszExt[3] == '\0')
5256 return kwFsIsCacheableExtensionCommon(wcFirst, wcSecond, wcThird, fAttrQuery);
5257 return K_FALSE;
5258 }
5259 return kwFsIsCacheableExtensionCommon(wcFirst, 0, 0, fAttrQuery);
5260 }
5261 return kwFsIsCacheableExtensionCommon(0, 0, 0, fAttrQuery);
44895262 }
44905263
44915264
44985271 * @param fAttrQuery Set if it's for an attribute query, clear if for
44995272 * file creation.
45005273 */
4501 static KBOOL kwFsIsCachablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery)
4502 {
4503 /*
4504 * Extract the extension, check that it's in the applicable range, roughly
4505 * convert it to ASCII/ANSI, and feed it to kwFsIsCachableExtensionA for
4506 * the actual check. This avoids a lot of code duplication.
4507 */
4508 wchar_t wc;
4509 char szExt[4];
5274 static KBOOL kwFsIsCacheablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery)
5275 {
45105276 KSIZE cwcExt;
45115277 wchar_t const *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt);
45125278 switch (cwcExt)
45135279 {
4514 case 3: if ((wchar_t)(szExt[2] = (char)(wc = pwszExt[2])) == wc) { /*likely*/ } else break;
4515 case 2: if ((wchar_t)(szExt[1] = (char)(wc = pwszExt[1])) == wc) { /*likely*/ } else break;
4516 case 1: if ((wchar_t)(szExt[0] = (char)(wc = pwszExt[0])) == wc) { /*likely*/ } else break;
4517 case 0:
4518 szExt[cwcExt] = '\0';
4519 return kwFsIsCachableExtensionA(szExt, fAttrQuery);
5280 case 3: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], pwszExt[2], fAttrQuery);
5281 case 2: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], 0, fAttrQuery);
5282 case 1: return kwFsIsCacheableExtensionCommon(pwszExt[0], 0, 0, fAttrQuery);
5283 case 0: return kwFsIsCacheableExtensionCommon(0, 0, 0, fAttrQuery);
45205284 }
45215285 return K_FALSE;
45225286 }
45755339 if (GetFileSizeEx(hFile, &cbFile))
45765340 {
45775341 if ( cbFile.QuadPart >= 0
4578 && cbFile.QuadPart < 16*1024*1024)
5342 #ifdef WITH_PCH_CACHING
5343 && ( cbFile.QuadPart < 16*1024*1024
5344 || ( cbFile.QuadPart < 96*1024*1024
5345 && pFsObj->cchName > 4
5346 && !g_Sandbox.fNoPchCaching
5347 && kHlpStrICompAscii(&pFsObj->pszName[pFsObj->cchName - 4], ".pch") == 0) )
5348 #endif
5349 )
45795350 {
45805351 KU32 cbCache = (KU32)cbFile.QuadPart;
4581 KU8 *pbCache = (KU8 *)kHlpAlloc(cbCache);
4582 if (pbCache)
5352 HANDLE hMapping = CreateFileMappingW(hFile, NULL /*pSecAttrs*/, PAGE_READONLY,
5353 0 /*cbMaxLow*/, 0 /*cbMaxHigh*/, NULL /*pwszName*/);
5354 if (hMapping != NULL)
45835355 {
4584 DWORD cbActually = 0;
4585 if ( ReadFile(hFile, pbCache, cbCache, &cbActually, NULL)
4586 && cbActually == cbCache)
5356 KU8 *pbCache = (KU8 *)MapViewOfFile(hMapping, FILE_MAP_READ, 0 /*offFileHigh*/, 0 /*offFileLow*/, cbCache);
5357 if (pbCache)
45875358 {
4588 LARGE_INTEGER offZero;
4589 offZero.QuadPart = 0;
4590 if (SetFilePointerEx(hFile, offZero, NULL /*poffNew*/, FILE_BEGIN))
5359 /*
5360 * Create the cached file object.
5361 */
5362 PKFSWCACHEDFILE pCachedFile;
5363 KU32 cbPath = pFsObj->cchParent + pFsObj->cchName + 2;
5364 pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE,
5365 sizeof(*pCachedFile) + cbPath);
5366 if (pCachedFile)
45915367 {
4592 /*
4593 * Create the cached file object.
4594 */
4595 PKFSWCACHEDFILE pCachedFile;
4596 KU32 cbPath = pFsObj->cchParent + pFsObj->cchName + 2;
4597 pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE,
4598 sizeof(*pCachedFile) + cbPath);
4599 if (pCachedFile)
4600 {
4601 pCachedFile->hCached = hFile;
4602 pCachedFile->cbCached = cbCache;
4603 pCachedFile->pbCached = pbCache;
4604 pCachedFile->pFsObj = pFsObj;
4605 kFsCacheObjGetFullPathA(pFsObj, pCachedFile->szPath, cbPath, '/');
4606 kFsCacheObjRetain(pFsObj);
4607 return pCachedFile;
4608 }
4609
4610 KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n"));
5368 pCachedFile->hCached = hFile;
5369 pCachedFile->hSection = hMapping;
5370 pCachedFile->cbCached = cbCache;
5371 pCachedFile->pbCached = pbCache;
5372 pCachedFile->pFsObj = pFsObj;
5373 kFsCacheObjGetFullPathA(pFsObj, pCachedFile->szPath, cbPath, '/');
5374 kFsCacheObjRetain(pFsObj);
5375
5376 g_cReadCachedFiles++;
5377 g_cbReadCachedFiles += cbCache;
5378
5379 KWFS_LOG(("Cached '%s': %p LB %#x, hCached=%p\n", pCachedFile->szPath, pbCache, cbCache, hFile));
5380 return pCachedFile;
46115381 }
4612 else
4613 KWFS_LOG(("Failed to seek to start of cached file! err=%u\n", GetLastError()));
5382
5383 KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n"));
46145384 }
46155385 else
4616 KWFS_LOG(("Failed to read %#x bytes into cache! err=%u cbActually=%#x\n",
4617 cbCache, GetLastError(), cbActually));
4618 kHlpFree(pbCache);
5386 KWFS_LOG(("Failed to cache file: MapViewOfFile failed: %u\n", GetLastError()));
5387 CloseHandle(hMapping);
46195388 }
46205389 else
4621 KWFS_LOG(("Failed to allocate %#x bytes for cache!\n", cbCache));
5390 KWFS_LOG(("Failed to cache file: CreateFileMappingW failed: %u\n", GetLastError()));
46225391 }
46235392 else
46245393 KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart));
46345403
46355404
46365405 /**
5406 * Kernel32 - Common code for kwFsObjCacheCreateFile and CreateFileMappingW/A.
5407 */
5408 static KBOOL kwFsObjCacheCreateFileHandle(PKFSWCACHEDFILE pCachedFile, DWORD dwDesiredAccess, BOOL fInheritHandle,
5409 KBOOL fIsFileHandle, HANDLE *phFile)
5410 {
5411 HANDLE hProcSelf = GetCurrentProcess();
5412 if (DuplicateHandle(hProcSelf, fIsFileHandle ? pCachedFile->hCached : pCachedFile->hSection,
5413 hProcSelf, phFile,
5414 dwDesiredAccess, fInheritHandle,
5415 0 /*dwOptions*/))
5416 {
5417 /*
5418 * Create handle table entry for the duplicate handle.
5419 */
5420 PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
5421 if (pHandle)
5422 {
5423 pHandle->enmType = fIsFileHandle ? KWHANDLETYPE_FSOBJ_READ_CACHE : KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING;
5424 pHandle->cRefs = 1;
5425 pHandle->offFile = 0;
5426 pHandle->hHandle = *phFile;
5427 pHandle->dwDesiredAccess = dwDesiredAccess;
5428 pHandle->u.pCachedFile = pCachedFile;
5429 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, pHandle->hHandle))
5430 return K_TRUE;
5431
5432 kHlpFree(pHandle);
5433 }
5434 else
5435 KWFS_LOG(("Out of memory for handle!\n"));
5436
5437 CloseHandle(*phFile);
5438 *phFile = INVALID_HANDLE_VALUE;
5439 }
5440 else
5441 KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError()));
5442 return K_FALSE;
5443 }
5444
5445
5446 /**
46375447 * Kernel32 - Common code for CreateFileW and CreateFileA.
46385448 */
46395449 static KBOOL kwFsObjCacheCreateFile(PKFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL fInheritHandle, HANDLE *phFile)
46405450 {
46415451 *phFile = INVALID_HANDLE_VALUE;
4642 kHlpAssert(pFsObj->fHaveStats);
46435452
46445453 /*
46455454 * At the moment we only handle existing files.
46475456 if (pFsObj->bObjType == KFSOBJ_TYPE_FILE)
46485457 {
46495458 PKFSWCACHEDFILE pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjGetUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE);
5459 kHlpAssert(pFsObj->fHaveStats);
46505460 if ( pCachedFile != NULL
46515461 || (pCachedFile = kwFsObjCacheNewFile(pFsObj)) != NULL)
46525462 {
4653 HANDLE hProcSelf = GetCurrentProcess();
4654 if (DuplicateHandle(hProcSelf, pCachedFile->hCached,
4655 hProcSelf, phFile,
4656 dwDesiredAccess, fInheritHandle,
4657 0 /*dwOptions*/))
4658 {
4659 /*
4660 * Create handle table entry for the duplicate handle.
4661 */
4662 PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
4663 if (pHandle)
4664 {
4665 pHandle->enmType = KWHANDLETYPE_FSOBJ_READ_CACHE;
4666 pHandle->offFile = 0;
4667 pHandle->hHandle = *phFile;
4668 pHandle->dwDesiredAccess = dwDesiredAccess;
4669 pHandle->u.pCachedFile = pCachedFile;
4670 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
4671 return K_TRUE;
4672
4673 kHlpFree(pHandle);
4674 }
4675 else
4676 KWFS_LOG(("Out of memory for handle!\n"));
4677
4678 CloseHandle(*phFile);
4679 *phFile = INVALID_HANDLE_VALUE;
4680 }
4681 else
4682 KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError()));
5463 if (kwFsObjCacheCreateFileHandle(pCachedFile, dwDesiredAccess, fInheritHandle, K_TRUE /*fIsFileHandle*/, phFile))
5464 return K_TRUE;
46835465 }
46845466 }
46855467 /** @todo Deal with non-existing files if it becomes necessary (it's not for VS2010). */
46955477 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
46965478 {
46975479 HANDLE hFile;
5480
5481 /*
5482 * Check for include files and similar that we do read-only caching of.
5483 */
46985484 if (dwCreationDisposition == FILE_OPEN_IF)
46995485 {
47005486 if ( dwDesiredAccess == GENERIC_READ
47075493 && pSecAttrs->lpSecurityDescriptor == NULL ) )
47085494 {
47095495 const char *pszExt = kHlpGetExt(pszFilename);
4710 if (kwFsIsCachableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
5496 if (kwFsIsCacheableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
47115497 {
47125498 KFSLOOKUPERROR enmError;
47135499 PKFSOBJ pFsObj;
47515537 }
47525538 }
47535539
5540 /*
5541 * Okay, normal.
5542 */
47545543 hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
47555544 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
5545 if (hFile != INVALID_HANDLE_VALUE)
5546 {
5547 kHlpAssert( KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles
5548 || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL);
5549 }
47565550 KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile));
47575551 return hFile;
47585552 }
47665560 HANDLE hFile;
47675561
47685562 #ifdef WITH_TEMP_MEMORY_FILES
4769 /* First check for temporary files (cl.exe only). */
5563 /*
5564 * Check for temporary files (cl.exe only).
5565 */
47705566 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
47715567 && !(dwFlagsAndAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_FLAG_BACKUP_SEMANTICS))
47725568 && !(dwDesiredAccess & (GENERIC_EXECUTE | FILE_EXECUTE))
47785574 }
47795575 #endif
47805576
4781 /* Then check for include files and similar. */
5577 /*
5578 * Check for include files and similar that we do read-only caching of.
5579 */
47825580 if (dwCreationDisposition == FILE_OPEN_IF)
47835581 {
47845582 if ( dwDesiredAccess == GENERIC_READ
47905588 || ( pSecAttrs->nLength == sizeof(*pSecAttrs)
47915589 && pSecAttrs->lpSecurityDescriptor == NULL ) )
47925590 {
4793 if (kwFsIsCachablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
5591 if (kwFsIsCacheablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
47945592 {
4795 /** @todo rewrite in pure UTF-16. */
4796 char szTmp[2048];
4797 KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
4798 if (cch < sizeof(szTmp))
4799 return kwSandbox_Kernel32_CreateFileA(szTmp, dwDesiredAccess, dwShareMode, pSecAttrs,
4800 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
5593 KFSLOOKUPERROR enmError;
5594 PKFSOBJ pFsObj;
5595 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5596
5597 pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError);
5598 if (pFsObj)
5599 {
5600 KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle,
5601 &hFile);
5602 kFsCacheObjRelease(g_pFsCache, pFsObj);
5603 if (fRc)
5604 {
5605 KWFS_LOG(("CreateFileW(%ls) -> %p [cached]\n", pwszFilename, hFile));
5606 return hFile;
5607 }
5608 }
5609 /* These are for nasm and yasm style header searching. Cache will
5610 already have checked the directories for the file, no need to call
5611 CreateFile to do it again. */
5612 else if (enmError == KFSLOOKUPERROR_NOT_FOUND)
5613 {
5614 KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_FILE_NOT_FOUND\n", pwszFilename));
5615 return INVALID_HANDLE_VALUE;
5616 }
5617 else if ( enmError == KFSLOOKUPERROR_PATH_COMP_NOT_FOUND
5618 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR)
5619 {
5620 KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_PATH_NOT_FOUND\n", pwszFilename));
5621 return INVALID_HANDLE_VALUE;
5622 }
5623
5624 /* fallback */
5625 hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
5626 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
5627 KWFS_LOG(("CreateFileW(%ls) -> %p (err=%u) [fallback]\n", pwszFilename, hFile, GetLastError()));
5628 return hFile;
48015629 }
48025630 }
48035631 else
48125640 }
48135641 else
48145642 KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition));
5643
5644 /*
5645 * Okay, normal.
5646 */
48155647 hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
48165648 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
5649 if (hFile != INVALID_HANDLE_VALUE)
5650 {
5651 kHlpAssert( KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles
5652 || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL);
5653 }
48175654 KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile));
48185655 return hFile;
48195656 }
48405677 case KWHANDLETYPE_TEMP_FILE:
48415678 cbFile = pHandle->u.pTempFile->cbFile;
48425679 break;
5680 #endif
48435681 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4844 #endif
5682 case KWHANDLETYPE_OUTPUT_BUF:
48455683 default:
48465684 kHlpAssertFailed();
48475685 SetLastError(ERROR_INVALID_FUNCTION);
48895727 }
48905728 if (pcbMoveHi)
48915729 *pcbMoveHi = (KU64)offMove >> 32;
4892 KWFS_LOG(("SetFilePointer(%p) -> %#llx [cached]\n", hFile, offMove));
5730 KWFS_LOG(("SetFilePointer(%p,%#x,?,%u) -> %#llx [%s]\n", hFile, cbMove, dwMoveMethod, offMove,
5731 pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp"));
48935732 SetLastError(NO_ERROR);
48945733 return (KU32)offMove;
48955734 }
48965735 }
4897 KWFS_LOG(("SetFilePointer(%p)\n", hFile));
5736 KWFS_LOG(("SetFilePointer(%p, %d, %p=%d, %d)\n", hFile, cbMove, pcbMoveHi ? *pcbMoveHi : 0, dwMoveMethod));
48985737 return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod);
48995738 }
49005739
49215760 case KWHANDLETYPE_TEMP_FILE:
49225761 cbFile = pHandle->u.pTempFile->cbFile;
49235762 break;
5763 #endif
49245764 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4925 #endif
5765 case KWHANDLETYPE_OUTPUT_BUF:
49265766 default:
49275767 kHlpAssertFailed();
49285768 SetLastError(ERROR_INVALID_FUNCTION);
49705810 }
49715811 if (poffNew)
49725812 poffNew->QuadPart = offMyMove;
4973 KWFS_LOG(("SetFilePointerEx(%p) -> TRUE, %#llx [cached]\n", hFile, offMyMove));
5813 KWFS_LOG(("SetFilePointerEx(%p,%#llx,,%u) -> TRUE, %#llx [%s]\n", hFile, offMove.QuadPart, dwMoveMethod, offMyMove,
5814 pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp"));
49745815 return TRUE;
49755816 }
49765817 }
49835824 static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPDWORD pcbActuallyRead,
49845825 LPOVERLAPPED pOverlapped)
49855826 {
5827 BOOL fRet;
49865828 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5829 g_cReadFileCalls++;
49875830 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
49885831 if (idxHandle < g_Sandbox.cHandles)
49895832 {
49985841 KU32 cbActually = pCachedFile->cbCached - pHandle->offFile;
49995842 if (cbActually > cbToRead)
50005843 cbActually = cbToRead;
5001 else if (cbActually < cbToRead) // debug debug debug
5002 kHlpMemSet((KU8 *)pvBuffer + cbActually, '\0', cbToRead - cbActually); // debug debug debug
50035844
50045845 #ifdef WITH_HASH_MD5_CACHE
50055846 if (g_Sandbox.pHashHead)
50165857
50175858 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
50185859 *pcbActuallyRead = cbActually;
5860
5861 g_cbReadFileFromReadCached += cbActually;
5862 g_cbReadFileTotal += cbActually;
5863 g_cReadFileFromReadCached++;
50195864
50205865 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually));
50215866 return TRUE;
50755920 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
50765921 *pcbActuallyRead = cbActually;
50775922
5923 g_cbReadFileTotal += cbActually;
5924 g_cbReadFileFromInMemTemp += cbActually;
5925 g_cReadFileFromInMemTemp++;
5926
50785927 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually));
50795928 return TRUE;
50805929 }
5930 #endif /* WITH_TEMP_MEMORY_FILES */
50815931
50825932 case KWHANDLETYPE_TEMP_FILE_MAPPING:
5083 #endif /* WITH_TEMP_MEMORY_FILES */
5933 case KWHANDLETYPE_OUTPUT_BUF:
50845934 default:
50855935 kHlpAssertFailed();
50865936 SetLastError(ERROR_INVALID_FUNCTION);
50905940 }
50915941 }
50925942
5093 KWFS_LOG(("ReadFile(%p)\n", hFile));
5094 return ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
5943 fRet = ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
5944 if (fRet && pcbActuallyRead)
5945 g_cbReadFileTotal += *pcbActuallyRead;
5946 KWFS_LOG(("ReadFile(%p,%p,%#x,,) -> %d, %#x\n", hFile, pvBuffer, cbToRead, fRet, pcbActuallyRead ? *pcbActuallyRead : 0));
5947 return fRet;
50955948 }
50965949
50975950
51145967 return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine);
51155968 }
51165969
5970 #ifdef WITH_STD_OUT_ERR_BUFFERING
5971
5972 /**
5973 * Write something to a handle, making sure everything is actually written.
5974 *
5975 * @param hHandle Where to write it to.
5976 * @param pchBuf What to write
5977 * @param cchToWrite How much to write.
5978 */
5979 static void kwSandboxOutBufWriteIt(HANDLE hFile, char const *pchBuf, KU32 cchToWrite)
5980 {
5981 if (cchToWrite > 0)
5982 {
5983 DWORD cchWritten = 0;
5984 if (WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL))
5985 {
5986 if (cchWritten == cchToWrite)
5987 { /* likely */ }
5988 else
5989 {
5990 do
5991 {
5992 pchBuf += cchWritten;
5993 cchToWrite -= cchWritten;
5994 cchWritten = 0;
5995 } while ( cchToWrite > 0
5996 && WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL));
5997 }
5998 }
5999 else
6000 kHlpAssertFailed();
6001 }
6002 }
6003
6004
6005 /**
6006 * Worker for WriteFile when the output isn't going to the console.
6007 *
6008 * @param pSandbox The sandbox.
6009 * @param pOutBuf The output buffer.
6010 * @param pchBuffer What to write.
6011 * @param cchToWrite How much to write.
6012 */
6013 static void kwSandboxOutBufWrite(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pOutBuf, const char *pchBuffer, KU32 cchToWrite)
6014 {
6015 if (pOutBuf->u.Fully.cchBufAlloc > 0)
6016 { /* likely */ }
6017 else
6018 {
6019 /* No realloc, max size is 64KB. */
6020 pOutBuf->u.Fully.cchBufAlloc = 0x10000;
6021 pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc);
6022 if (!pOutBuf->u.Fully.pchBuf)
6023 {
6024 while ( !pOutBuf->u.Fully.pchBuf
6025 && pOutBuf->u.Fully.cchBufAlloc > 64)
6026 {
6027 pOutBuf->u.Fully.cchBufAlloc /= 2;
6028 pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc);
6029 }
6030 if (!pOutBuf->u.Fully.pchBuf)
6031 {
6032 pOutBuf->u.Fully.cchBufAlloc = sizeof(pOutBuf->abPadding);
6033 pOutBuf->u.Fully.pchBuf = pOutBuf->abPadding;
6034 }
6035 }
6036 }
6037
6038 /*
6039 * Special case: Output ends with newline and fits in the buffer.
6040 */
6041 if ( cchToWrite > 1
6042 && pchBuffer[cchToWrite - 1] == '\n'
6043 && cchToWrite <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf)
6044 {
6045 kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchToWrite);
6046 pOutBuf->u.Fully.cchBuf += cchToWrite;
6047 }
6048 else
6049 {
6050 /*
6051 * Work thru the text line by line, flushing the buffer when
6052 * appropriate. The buffer is not a line buffer here, it's a
6053 * full buffer.
6054 */
6055 while (cchToWrite > 0)
6056 {
6057 char const *pchNewLine = (const char *)memchr(pchBuffer, '\n', cchToWrite);
6058 KU32 cchLine = pchNewLine ? (KU32)(pchNewLine - pchBuffer) + 1 : cchToWrite;
6059 if (cchLine <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf)
6060 {
6061 kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchLine);
6062 pOutBuf->u.Fully.cchBuf += cchLine;
6063 }
6064 /*
6065 * Option one: Flush the buffer and the current line.
6066 *
6067 * We choose this one when the line won't ever fit, or when we have
6068 * an incomplete line in the buffer.
6069 */
6070 else if ( cchLine >= pOutBuf->u.Fully.cchBufAlloc
6071 || pOutBuf->u.Fully.cchBuf == 0
6072 || pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf - 1] != '\n')
6073 {
6074 KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes, writing %u bytes\n", pOutBuf->u.Fully.cchBuf, cchLine));
6075 if (pOutBuf->u.Fully.cchBuf > 0)
6076 {
6077 kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf);
6078 pOutBuf->u.Fully.cchBuf = 0;
6079 }
6080 kwSandboxOutBufWriteIt(pOutBuf->hBackup, pchBuffer, cchLine);
6081 }
6082 /*
6083 * Option two: Only flush the lines in the buffer.
6084 */
6085 else
6086 {
6087 KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes\n", pOutBuf->u.Fully.cchBuf));
6088 kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf);
6089 kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[0], pchBuffer, cchLine);
6090 pOutBuf->u.Fully.cchBuf = cchLine;
6091 }
6092
6093 /* advance */
6094 pchBuffer += cchLine;
6095 cchToWrite -= cchLine;
6096 }
6097 }
6098 }
6099
6100 #endif /* WITH_STD_OUT_ERR_BUFFERING */
6101
51176102 #ifdef WITH_TEMP_MEMORY_FILES
5118
51196103 static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded)
51206104 {
51216105 KU32 cbMinFile = offFile + cbNeeded;
51706154 kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded));
51716155 return K_FALSE;
51726156 }
5173
5174
6157 #endif /* WITH_TEMP_MEMORY_FILES */
6158
6159
6160 #if defined(WITH_TEMP_MEMORY_FILES) || defined(WITH_STD_OUT_ERR_BUFFERING)
51756161 /** Kernel32 - WriteFile */
51766162 static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten,
51776163 LPOVERLAPPED pOverlapped)
51786164 {
6165 BOOL fRet;
51796166 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5180 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6167 g_cWriteFileCalls++;
6168 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_fCtrlC);
51816169 if (idxHandle < g_Sandbox.cHandles)
51826170 {
51836171 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
51856173 {
51866174 switch (pHandle->enmType)
51876175 {
6176 # ifdef WITH_TEMP_MEMORY_FILES
51886177 case KWHANDLETYPE_TEMP_FILE:
51896178 {
51906179 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
52306219 pTempFile->cbFile = pHandle->offFile;
52316220
52326221 *pcbActuallyWritten = cbToWrite;
6222
6223 g_cbWriteFileTotal += cbToWrite;
6224 g_cbWriteFileToInMemTemp += cbToWrite;
6225 g_cWriteFileToInMemTemp++;
6226
52336227 KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite));
52346228 return TRUE;
52356229 }
52396233 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
52406234 return FALSE;
52416235 }
6236 # endif
52426237
52436238 case KWHANDLETYPE_FSOBJ_READ_CACHE:
52446239 kHlpAssertFailed();
52456240 SetLastError(ERROR_ACCESS_DENIED);
52466241 *pcbActuallyWritten = 0;
52476242 return FALSE;
6243
6244 # if defined(WITH_STD_OUT_ERR_BUFFERING) || defined(WITH_CONSOLE_OUTPUT_BUFFERING)
6245 /*
6246 * Standard output & error.
6247 */
6248 case KWHANDLETYPE_OUTPUT_BUF:
6249 {
6250 PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf;
6251 if (pOutBuf->fIsConsole)
6252 {
6253 kwSandboxConsoleWriteA(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite);
6254 KWOUT_LOG(("WriteFile(%p [console]) -> TRUE\n", hFile));
6255 }
6256 else
6257 {
6258 # ifdef WITH_STD_OUT_ERR_BUFFERING
6259 kwSandboxOutBufWrite(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite);
6260 KWOUT_LOG(("WriteFile(%p [std%s], 's*.*', %#x) -> TRUE\n", hFile,
6261 pOutBuf == &g_Sandbox.StdErr ? "err" : "out", cbToWrite, cbToWrite, pvBuffer, cbToWrite));
6262 # else
6263 kHlpAssertFailed();
6264 # endif
6265 }
6266 if (pcbActuallyWritten)
6267 *pcbActuallyWritten = cbToWrite;
6268 g_cbWriteFileTotal += cbToWrite;
6269 return TRUE;
6270 }
6271 # endif
52486272
52496273 default:
52506274 case KWHANDLETYPE_TEMP_FILE_MAPPING:
52566280 }
52576281 }
52586282
5259 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
5260 /*
5261 * Check for stdout and stderr.
5262 */
5263 if ( g_Sandbox.StdErr.hOutput == hFile
5264 || g_Sandbox.StdOut.hOutput == hFile)
5265 {
5266 PKWCONSOLEOUTPUTLINE pLineBuf = g_Sandbox.StdErr.hOutput == hFile ? &g_Sandbox.StdErr : &g_Sandbox.StdOut;
5267 if (pLineBuf->fIsConsole)
5268 {
5269 kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (const char *)pvBuffer, cbToWrite);
5270 KWFS_LOG(("WriteFile(console) -> TRUE\n", hFile));
5271 return TRUE;
5272 }
5273 }
5274 #endif
5275
5276 KWFS_LOG(("WriteFile(%p)\n", hFile));
5277 return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
6283 fRet = WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
6284 if (fRet && pcbActuallyWritten)
6285 g_cbWriteFileTotal += *pcbActuallyWritten;
6286 KWFS_LOG(("WriteFile(%p,,%#x) -> %d, %#x\n", hFile, cbToWrite, fRet, pcbActuallyWritten ? *pcbActuallyWritten : 0));
6287 return fRet;
52786288 }
52796289
52806290
52976307 return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine);
52986308 }
52996309
6310 #endif /* WITH_TEMP_MEMORY_FILES || WITH_STD_OUT_ERR_BUFFERING */
6311
6312 #ifdef WITH_TEMP_MEMORY_FILES
53006313
53016314 /** Kernel32 - SetEndOfFile; */
53026315 static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
53316344 SetLastError(ERROR_ACCESS_DENIED);
53326345 return FALSE;
53336346
6347 case KWHANDLETYPE_OUTPUT_BUF:
6348 kHlpAssertFailed();
6349 SetLastError(pHandle->u.pOutBuf->fIsConsole ? ERROR_INVALID_OPERATION : ERROR_ACCESS_DENIED);
6350 return FALSE;
6351
53346352 default:
53356353 case KWHANDLETYPE_TEMP_FILE_MAPPING:
53366354 kHlpAssertFailed();
53646382 case KWHANDLETYPE_TEMP_FILE:
53656383 KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile));
53666384 return FILE_TYPE_DISK;
6385
6386 case KWHANDLETYPE_OUTPUT_BUF:
6387 {
6388 PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf;
6389 DWORD fRet;
6390 if (pOutBuf->fFileType != KU8_MAX)
6391 {
6392 fRet = (pOutBuf->fFileType & 0xf) | ((pOutBuf->fFileType & (FILE_TYPE_REMOTE >> 8)) << 8);
6393 KWFS_LOG(("GetFileType(%p) -> %#x [outbuf]\n", hFile, fRet));
6394 }
6395 else
6396 {
6397 fRet = GetFileType(hFile);
6398 KWFS_LOG(("GetFileType(%p) -> %#x [outbuf, fallback]\n", hFile, fRet));
6399 }
6400 return fRet;
6401 }
6402
53676403 }
53686404 }
53696405 }
53966432 KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
53976433 return pHandle->u.pTempFile->cbFile;
53986434
6435 case KWHANDLETYPE_OUTPUT_BUF:
6436 /* do default */
6437 break;
6438
53996439 default:
54006440 kHlpAssertFailed();
54016441 SetLastError(ERROR_INVALID_FUNCTION);
54316471 pcbFile->QuadPart = pHandle->u.pTempFile->cbFile;
54326472 return TRUE;
54336473
6474 case KWHANDLETYPE_OUTPUT_BUF:
6475 /* do default */
6476 break;
6477
54346478 default:
54356479 kHlpAssertFailed();
54366480 SetLastError(ERROR_INVALID_FUNCTION);
54446488 }
54456489
54466490
5447 /** Kernel32 - CreateFileMapping */
6491 /** Kernel32 - CreateFileMappingW */
54486492 static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs,
54496493 DWORD fProtect, DWORD dwMaximumSizeHigh,
54506494 DWORD dwMaximumSizeLow, LPCWSTR pwszName)
54516495 {
6496 HANDLE hMapping;
54526497 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
54536498 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
54546499 if (idxHandle < g_Sandbox.cHandles)
54686513 || dwMaximumSizeLow == pTempFile->cbFile)
54696514 && pwszName == NULL)
54706515 {
5471 HANDLE hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
6516 hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
54726517 KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping));
54736518 return hMapping;
54746519 }
54776522 SetLastError(ERROR_ACCESS_DENIED);
54786523 return INVALID_HANDLE_VALUE;
54796524 }
5480 }
5481 }
5482 }
5483
5484 KWFS_LOG(("CreateFileMappingW(%p)\n", hFile));
5485 return CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
5486 }
6525
6526 /* moc.exe benefits from this. */
6527 case KWHANDLETYPE_FSOBJ_READ_CACHE:
6528 {
6529 PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile;
6530 if ( ( fProtect == PAGE_READONLY
6531 || fProtect == PAGE_EXECUTE_READ)
6532 && dwMaximumSizeHigh == 0
6533 && ( dwMaximumSizeLow == 0
6534 || dwMaximumSizeLow == pCachedFile->cbCached)
6535 && pwszName == NULL)
6536 {
6537 if (kwFsObjCacheCreateFileHandle(pCachedFile, GENERIC_READ, FALSE /*fInheritHandle*/,
6538 K_FALSE /*fIsFileHandle*/, &hMapping))
6539 { /* likely */ }
6540 else
6541 hMapping = NULL;
6542 KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [cached]\n", hFile, fProtect, hMapping));
6543 return hMapping;
6544 }
6545
6546 /* Do fallback (for .pch). */
6547 kHlpAssertMsg(fProtect == PAGE_WRITECOPY,
6548 ("fProtect=%#x cb=%#x'%08x name=%p\n",
6549 fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName));
6550
6551 hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
6552 KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p [cached-fallback]\n",
6553 hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping));
6554 return hMapping;
6555 }
6556
6557 /** @todo read cached memory mapped files too for moc. */
6558 }
6559 }
6560 }
6561
6562 hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
6563 KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p\n",
6564 hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping));
6565 return hMapping;
6566 }
6567
54876568
54886569 /** Kernel32 - MapViewOfFile */
5489 static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
5490 DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
5491 {
6570 static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
6571 DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
6572 {
6573 PVOID pvRet;
54926574 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
54936575 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
54946576 if (idxHandle < g_Sandbox.cHandles)
54966578 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
54976579 if (pHandle != NULL)
54986580 {
6581 KU32 idxMapping;
6582
6583 /*
6584 * Ensure one free entry in the mapping tracking table first,
6585 * since this is common to both temporary and cached files.
6586 */
6587 if (g_Sandbox.cMemMappings + 1 <= g_Sandbox.cMemMappingsAlloc)
6588 { /* likely */ }
6589 else
6590 {
6591 void *pvNew;
6592 KU32 cNew = g_Sandbox.cMemMappingsAlloc;
6593 if (cNew)
6594 cNew *= 2;
6595 else
6596 cNew = 32;
6597 pvNew = kHlpRealloc(g_Sandbox.paMemMappings, cNew * sizeof(g_Sandbox.paMemMappings));
6598 if (pvNew)
6599 g_Sandbox.paMemMappings = (PKWMEMMAPPING)pvNew;
6600 else
6601 {
6602 kwErrPrintf("Failed to grow paMemMappings from %#x to %#x!\n", g_Sandbox.cMemMappingsAlloc, cNew);
6603 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
6604 return NULL;
6605 }
6606 g_Sandbox.cMemMappingsAlloc = cNew;
6607 }
6608
6609 /*
6610 * Type specific work.
6611 */
54996612 switch (pHandle->enmType)
55006613 {
55016614 case KWHANDLETYPE_FSOBJ_READ_CACHE:
55026615 case KWHANDLETYPE_TEMP_FILE:
6616 case KWHANDLETYPE_OUTPUT_BUF:
6617 default:
55036618 kHlpAssertFailed();
5504 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
6619 SetLastError(ERROR_INVALID_OPERATION);
55056620 return NULL;
55066621
55076622 case KWHANDLETYPE_TEMP_FILE_MAPPING:
55526667 pTempFile->cMappings++;
55536668 kHlpAssert(pTempFile->cMappings == 1);
55546669
5555 KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pTempFile->paSegs[0].pbData));
5556 return pTempFile->paSegs[0].pbData;
6670 pvRet = pTempFile->paSegs[0].pbData;
6671 KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pvRet));
6672 break;
55576673 }
55586674
55596675 kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
55616677 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
55626678 return NULL;
55636679 }
5564 }
5565 }
5566 }
5567
5568 KWFS_LOG(("MapViewOfFile(%p)\n", hSection));
5569 return MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
5570 }
5571 /** @todo MapViewOfFileEx */
5572
6680
6681 /*
6682 * This is simple in comparison to the above temporary file code.
6683 */
6684 case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING:
6685 {
6686 PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile;
6687 if ( dwDesiredAccess == FILE_MAP_READ
6688 && offFileHigh == 0
6689 && offFileLow == 0
6690 && (cbToMap == 0 || cbToMap == pCachedFile->cbCached) )
6691 {
6692 pvRet = pCachedFile->pbCached;
6693 KWFS_LOG(("CreateFileMappingW(%p) -> %p [cached]\n", hSection, pvRet));
6694 break;
6695 }
6696 kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
6697 dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pCachedFile->cbCached));
6698 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
6699 return NULL;
6700 }
6701 }
6702
6703 /*
6704 * Insert into the mapping tracking table. This is common
6705 * and we should only get here with a non-NULL pvRet.
6706 *
6707 * Note! We could look for duplicates and do ref counting, but it's
6708 * easier to just append for now.
6709 */
6710 kHlpAssert(pvRet != NULL);
6711 idxMapping = g_Sandbox.cMemMappings;
6712 kHlpAssert(idxMapping < g_Sandbox.cMemMappingsAlloc);
6713
6714 g_Sandbox.paMemMappings[idxMapping].cRefs = 1;
6715 g_Sandbox.paMemMappings[idxMapping].pvMapping = pvRet;
6716 g_Sandbox.paMemMappings[idxMapping].enmType = pHandle->enmType;
6717 g_Sandbox.paMemMappings[idxMapping].u.pCachedFile = pHandle->u.pCachedFile;
6718 g_Sandbox.cMemMappings++;
6719
6720 return pvRet;
6721 }
6722 }
6723
6724 pvRet = MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
6725 KWFS_LOG(("MapViewOfFile(%p, %#x, %#x, %#x, %#x) -> %p\n",
6726 hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvRet));
6727 return pvRet;
6728 }
6729
6730
6731 /** Kernel32 - MapViewOfFileEx */
6732 static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFileEx(HANDLE hSection, DWORD dwDesiredAccess,
6733 DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap, PVOID pvMapAddr)
6734 {
6735 PVOID pvRet;
6736 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
6737 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6738 if (idxHandle < g_Sandbox.cHandles)
6739 {
6740 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
6741 if (pHandle != NULL)
6742 {
6743 switch (pHandle->enmType)
6744 {
6745 case KWHANDLETYPE_TEMP_FILE_MAPPING:
6746 KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - temporary file!\n",
6747 hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr));
6748 if (!pvMapAddr)
6749 return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
6750 kHlpAssertFailed();
6751 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
6752 return NULL;
6753
6754 case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING:
6755 KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - read cached file!\n",
6756 hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr));
6757 if (!pvMapAddr)
6758 return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
6759 /* We can use fallback here as the handle is an actual section handle. */
6760 break;
6761
6762 case KWHANDLETYPE_FSOBJ_READ_CACHE:
6763 case KWHANDLETYPE_TEMP_FILE:
6764 case KWHANDLETYPE_OUTPUT_BUF:
6765 default:
6766 kHlpAssertFailed();
6767 SetLastError(ERROR_INVALID_OPERATION);
6768 return NULL;
6769 }
6770 }
6771 }
6772
6773 pvRet = MapViewOfFileEx(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr);
6774 KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) -> %p\n",
6775 hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr, pvRet));
6776 return pvRet;
6777
6778 }
55736779
55746780 /** Kernel32 - UnmapViewOfFile */
55756781 static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
55766782 {
5577 /* Is this one of our temporary mappings? */
5578 PKWFSTEMPFILE pCur = g_Sandbox.pTempFileHead;
6783 /*
6784 * Consult the memory mapping tracker.
6785 */
6786 PKWMEMMAPPING paMemMappings = g_Sandbox.paMemMappings;
6787 KU32 idxMapping = g_Sandbox.cMemMappings;
55796788 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5580 while (pCur)
5581 {
5582 if ( pCur->cMappings > 0
5583 && pCur->paSegs[0].pbData == (KU8 *)pvBase)
5584 {
5585 pCur->cMappings--;
5586 KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
6789 while (idxMapping-- > 0)
6790 if (paMemMappings[idxMapping].pvMapping == pvBase)
6791 {
6792 /* Type specific stuff. */
6793 if (paMemMappings[idxMapping].enmType == KWHANDLETYPE_TEMP_FILE_MAPPING)
6794 {
6795 KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
6796 paMemMappings[idxMapping].u.pTempFile->cMappings--;
6797 }
6798 else
6799 KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [cached]\n", pvBase));
6800
6801 /* Deref and probably free it. */
6802 if (--paMemMappings[idxMapping].cRefs == 0)
6803 {
6804 g_Sandbox.cMemMappings--;
6805 if (idxMapping != g_Sandbox.cMemMappings)
6806 paMemMappings[idxMapping] = paMemMappings[g_Sandbox.cMemMappings];
6807 }
55876808 return TRUE;
55886809 }
5589 pCur = pCur->pNext;
5590 }
55916810
55926811 KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase));
55936812 return UnmapViewOfFile(pvBase);
55956814
55966815 /** @todo UnmapViewOfFileEx */
55976816
5598
55996817 #endif /* WITH_TEMP_MEMORY_FILES */
6818
6819
6820 /** Kernel32 - DuplicateHandle */
6821 static BOOL WINAPI kwSandbox_Kernel32_DuplicateHandle(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, PHANDLE phNew,
6822 DWORD dwDesiredAccess, BOOL fInheritHandle, DWORD dwOptions)
6823 {
6824 BOOL fRet;
6825
6826 /*
6827 * We must catch our handles being duplicated.
6828 */
6829 if (hSrcProc == GetCurrentProcess())
6830 {
6831 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSrc);
6832 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6833 if (idxHandle < g_Sandbox.cHandles)
6834 {
6835 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
6836 if (pHandle)
6837 {
6838 fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions);
6839 if (fRet)
6840 {
6841 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, *phNew))
6842 {
6843 pHandle->cRefs++;
6844 KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> TRUE, %p [intercepted handle] enmType=%d cRef=%d\n",
6845 hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew,
6846 pHandle->enmType, pHandle->cRefs));
6847 }
6848 else
6849 {
6850 fRet = FALSE;
6851 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
6852 KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> !FALSE!, %p [intercepted handle] enmType=%d\n",
6853 hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew, pHandle->enmType));
6854 }
6855 }
6856 else
6857 KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> FALSE [intercepted handle] enmType=%d\n",
6858 hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, pHandle->enmType));
6859 return fRet;
6860 }
6861 }
6862 }
6863
6864 /*
6865 * Not one of ours, just do what the caller asks and log it.
6866 */
6867 fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions);
6868 KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> %d, %p\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess,
6869 fInheritHandle, dwOptions, fRet, *phNew));
6870 return fRet;
6871 }
6872
56006873
56016874 /** Kernel32 - CloseHandle */
56026875 static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject)
56036876 {
56046877 BOOL fRet;
56056878 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
5606 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5607 if ( idxHandle < g_Sandbox.cHandles
5608 && g_Sandbox.papHandles[idxHandle] != NULL)
5609 {
5610 fRet = CloseHandle(hObject);
5611 if (fRet)
5612 {
5613 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5614 g_Sandbox.papHandles[idxHandle] = NULL;
5615 g_Sandbox.cActiveHandles--;
6879 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_fCtrlC);
6880 if (idxHandle < g_Sandbox.cHandles)
6881 {
6882 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
6883 if (pHandle)
6884 {
6885 /* Prevent the closing of the standard output and error handles. */
6886 if ( pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF
6887 || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle))
6888 {
6889 fRet = CloseHandle(hObject);
6890 if (fRet)
6891 {
6892 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
6893 g_Sandbox.papHandles[idxHandle] = NULL;
6894 g_Sandbox.cActiveHandles--;
6895 kHlpAssert(g_Sandbox.cActiveHandles >= g_Sandbox.cFixedHandles);
6896 if (--pHandle->cRefs == 0)
6897 {
56166898 #ifdef WITH_TEMP_MEMORY_FILES
5617 if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
5618 {
5619 kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
5620 pHandle->u.pTempFile->cActiveHandles--;
5621 }
6899 if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
6900 {
6901 kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
6902 pHandle->u.pTempFile->cActiveHandles--;
6903 }
56226904 #endif
5623 kHlpFree(pHandle);
5624 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));
5625 }
5626 else
5627 KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
5628 }
5629 else
5630 {
5631 KWFS_LOG(("CloseHandle(%p)\n", hObject));
5632 fRet = CloseHandle(hObject);
5633 }
6905 kHlpFree(pHandle);
6906 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, freed]\n", hObject));
6907 }
6908 else
6909 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, not freed]\n", hObject));
6910 }
6911 else
6912 KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
6913 }
6914 else
6915 {
6916 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle] Ignored closing of std%s!\n",
6917 hObject, hObject == g_Sandbox.StdErr.hOutput ? "err" : "out"));
6918 fRet = TRUE;
6919 }
6920 return fRet;
6921 }
6922 }
6923
6924 fRet = CloseHandle(hObject);
6925 KWFS_LOG(("CloseHandle(%p) -> %d\n", hObject, fRet));
56346926 return fRet;
56356927 }
56366928
56406932 {
56416933 DWORD fRet;
56426934 const char *pszExt = kHlpGetExt(pszFilename);
5643 if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
6935 if (kwFsIsCacheableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
56446936 {
56456937 KFSLOOKUPERROR enmError;
56466938 PKFSOBJ pFsObj;
56736965 static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
56746966 {
56756967 DWORD fRet;
5676 if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
6968 if (kwFsIsCacheablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
56776969 {
56786970 KFSLOOKUPERROR enmError;
56796971 PKFSOBJ pFsObj;
57087000 static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath)
57097001 {
57107002 DWORD cwcRet;
5711 if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
7003 if (kwFsIsCacheablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
57127004 {
57137005 KFSLOOKUPERROR enmError;
57147006 PKFSOBJ pObj;
58137105 {
58147106 off += cwcWritten;
58157107 cwcWritten = 0;
5816 }
5817 while ( off < cwcToWrite
5818 && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL));
7108 } while ( off < cwcToWrite
7109 && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL));
58197110 kHlpAssert(off == cwcWritten);
58207111 }
58217112 }
58357126 {
58367127 if (pSandbox->Combined.cwcBuf > 0)
58377128 {
7129 KWOUT_LOG(("kwSandboxConsoleFlushCombined: %u wchars\n", pSandbox->Combined.cwcBuf));
58387130 kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf);
58397131 pSandbox->Combined.cwcBuf = 0;
58407132 }
58617153 }
58627154 else
58637155 {
5864 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t));
7156 kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t));
58657157 pSandbox->Combined.cwcBuf += cwcBuf;
58667158 }
58677159 }
58727164 *
58737165 * @param pSandbox The sandbox.
58747166 * @param pLineBuf The line buffer.
5875 */
5876 static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf)
5877 {
5878 if (pLineBuf->cwcBuf > 0)
5879 {
5880 if (pLineBuf->fIsConsole)
5881 {
5882 if (pLineBuf->cwcBuf < pLineBuf->cwcBufAlloc)
5883 {
5884 pLineBuf->pwcBuf[pLineBuf->cwcBuf++] = '\n';
5885 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_FALSE /*fBrokenLine*/);
7167 * @param pszName The line buffer name (for logging)
7168 */
7169 static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pszName)
7170 {
7171 if (pLineBuf->fIsConsole)
7172 {
7173 if (pLineBuf->u.Con.cwcBuf > 0)
7174 {
7175 KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u wchars\n", pszName, pLineBuf->u.Con.cwcBuf));
7176
7177 if (pLineBuf->u.Con.cwcBuf < pLineBuf->u.Con.cwcBufAlloc)
7178 {
7179 pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf++] = '\n';
7180 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_FALSE /*fBrokenLine*/);
58867181 }
58877182 else
58887183 {
5889 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
7184 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/);
58907185 kwSandboxConsoleAddToCombined(pSandbox, L"\n", 1, K_TRUE /*fBrokenLine*/);
58917186 }
5892 pLineBuf->cwcBuf = 0;
5893 }
5894 else
5895 {
5896 kHlpAssertFailed();
5897 }
5898 }
7187 pLineBuf->u.Con.cwcBuf = 0;
7188 }
7189 }
7190 #ifdef WITH_STD_OUT_ERR_BUFFERING
7191 else if (pLineBuf->u.Fully.cchBuf > 0)
7192 {
7193 KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u bytes\n", pszName, pLineBuf->u.Fully.cchBuf));
7194
7195 kwSandboxOutBufWriteIt(pLineBuf->hBackup, pLineBuf->u.Fully.pchBuf, pLineBuf->u.Fully.cchBuf);
7196 pLineBuf->u.Fully.cchBuf = 0;
7197 }
7198 #endif
58997199 }
59007200
59017201
59087208 {
59097209 /*
59107210 * First do the cl.exe source file supression trick, if applicable.
7211 * The output ends up on CONOUT$ if either StdOut or StdErr is a console
7212 * handle.
59117213 */
5912 if ( pSandbox->Combined.cwcBuf >= 3
5913 && pSandbox->StdOut.cwcBuf == 0
5914 && pSandbox->StdErr.cwcBuf == 0
5915 && pSandbox->Combined.cFlushes == 0
5916 && pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
5917 {
5918 KI32 off = pSandbox->Combined.cwcBuf - 1;
5919 if (pSandbox->Combined.wszBuf[off] == '\n')
5920 {
5921 KBOOL fOk = K_TRUE;
5922 while (off-- > 0)
5923 {
5924 wchar_t const wc = pSandbox->Combined.wszBuf[off];
5925 if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-')
5926 { /* likely */ }
5927 else
7214 if ( pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
7215 && pSandbox->Combined.cFlushes == 0)
7216 {
7217 if ( pSandbox->StdOut.fIsConsole
7218 || pSandbox->StdErr.fIsConsole)
7219 {
7220 if ( pSandbox->Combined.cwcBuf >= 3
7221 && (pSandbox->StdOut.fIsConsole ? pSandbox->StdOut.u.Con.cwcBuf : pSandbox->StdOut.u.Fully.cchBuf) == 0
7222 && (pSandbox->StdErr.fIsConsole ? pSandbox->StdErr.u.Con.cwcBuf : pSandbox->StdErr.u.Fully.cchBuf) == 0 )
7223 {
7224 KI32 off = pSandbox->Combined.cwcBuf - 1;
7225 if (pSandbox->Combined.wszBuf[off] == '\n')
59287226 {
5929 fOk = K_FALSE;
5930 break;
7227 KBOOL fOk = K_TRUE;
7228 while (off-- > 0)
7229 {
7230 wchar_t const wc = pSandbox->Combined.wszBuf[off];
7231 if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-')
7232 { /* likely */ }
7233 else
7234 {
7235 fOk = K_FALSE;
7236 break;
7237 }
7238 }
7239 if (fOk)
7240 {
7241 KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*ls in combined console buffer\n",
7242 pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf));
7243 pSandbox->Combined.cwcBuf = 0;
7244 return;
7245 }
59317246 }
5932 }
5933 if (fOk)
5934 {
5935 pSandbox->Combined.cwcBuf = 0;
5936 return;
5937 }
5938 }
7247 KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*ls in combined console buffer\n",
7248 pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf));
7249 }
7250 }
7251 #ifdef WITH_STD_OUT_ERR_BUFFERING
7252 /*
7253 * Otherwise, it goes to standard output (redirected).
7254 */
7255 else if ( pSandbox->StdErr.u.Fully.cchBuf == 0
7256 && pSandbox->StdOut.u.Fully.cchBuf >= 3)
7257 {
7258 char const *pchBuf = pSandbox->StdOut.u.Fully.pchBuf;
7259 KI32 off = pSandbox->StdOut.u.Fully.cchBuf - 1;
7260 kHlpAssert(pSandbox->Combined.cFlushes == 0 && pSandbox->Combined.cwcBuf == 0); /* unused! */
7261
7262 if (pchBuf[off] == '\n')
7263 {
7264 KBOOL fOk = K_TRUE;
7265 if (pchBuf[off - 1] == '\r')
7266 off--;
7267 while (off-- > 0)
7268 {
7269 char const ch = pchBuf[off];
7270 if (isalnum(ch) || ch == '.' || ch == ' ' || ch == '_' || ch == '-')
7271 { /* likely */ }
7272 else
7273 {
7274 fOk = K_FALSE;
7275 break;
7276 }
7277 }
7278 if (fOk)
7279 {
7280 KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*s in stdout buffer\n",
7281 pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf));
7282 pSandbox->StdOut.u.Fully.cchBuf = 0;
7283 return;
7284 }
7285 }
7286 KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*s in stdout buffer\n",
7287 pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf));
7288 }
7289 #endif
59397290 }
59407291
59417292 /*
59427293 * Flush the two line buffer, the the combined buffer.
59437294 */
5944 kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr);
5945 kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut);
7295 kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr, "StdErr");
7296 kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut, "StdOut");
59467297 kwSandboxConsoleFlushCombined(pSandbox);
59477298 }
59487299
59557306 * @param pwcBuffer The buffer to write.
59567307 * @param cwcToWrite The number of wchar_t's in the buffer.
59577308 */
5958 static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
5959 {
7309 static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
7310 {
7311 kHlpAssert(pLineBuf->fIsConsole);
59607312 if (cwcToWrite > 0)
59617313 {
59627314 /*
59747326 if (offLastIncompleteLine < cwcToWrite)
59757327 {
59767328 /* Need to grow the line buffer? */
5977 KU32 cwcNeeded = offLastIncompleteLine != 0 ? offLastIncompleteLine : cchLastIncompleteLine + pLineBuf->cwcBuf;
5978 if (cwcNeeded > pLineBuf->cwcBufAlloc)
7329 KU32 cwcNeeded = offLastIncompleteLine == 0
7330 ? pLineBuf->u.Con.cwcBuf + cchLastIncompleteLine /* incomplete line, append to line buffer */
7331 : cchLastIncompleteLine; /* Only the final incomplete line (if any) goes to the line buffer. */
7332 if (cwcNeeded > pLineBuf->u.Con.cwcBufAlloc)
59797333 {
59807334 void *pvNew;
5981 KU32 cwcNew = !pLineBuf->cwcBufAlloc ? 1024 : pLineBuf->cwcBufAlloc * 2;
7335 KU32 cwcNew = !pLineBuf->u.Con.cwcBufAlloc ? 1024 : pLineBuf->u.Con.cwcBufAlloc * 2;
59827336 while (cwcNew < cwcNeeded)
59837337 cwcNew *= 2;
5984 pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNew * sizeof(wchar_t));
7338 pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNew * sizeof(wchar_t));
59857339 if (pvNew)
59867340 {
5987 pLineBuf->pwcBuf = (wchar_t *)pvNew;
5988 pLineBuf->cwcBufAlloc = cwcNew;
7341 pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew;
7342 pLineBuf->u.Con.cwcBufAlloc = cwcNew;
59897343 }
59907344 else
59917345 {
5992 pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNeeded * sizeof(wchar_t));
7346 pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNeeded * sizeof(wchar_t));
59937347 if (pvNew)
59947348 {
5995 pLineBuf->pwcBuf = (wchar_t *)pvNew;
5996 pLineBuf->cwcBufAlloc = cwcNeeded;
7349 pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew;
7350 pLineBuf->u.Con.cwcBufAlloc = cwcNeeded;
59977351 }
59987352 else
59997353 {
60007354 /* This isn't perfect, but it will have to do for now. */
6001 if (pLineBuf->cwcBuf > 0)
7355 if (pLineBuf->u.Con.cwcBuf > 0)
60027356 {
6003 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
6004 pLineBuf->cwcBuf = 0;
7357 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf,
7358 K_TRUE /*fBrokenLine*/);
7359 pLineBuf->u.Con.cwcBuf = 0;
60057360 }
60067361 kwSandboxConsoleAddToCombined(pSandbox, pwcBuffer, cwcToWrite, K_TRUE /*fBrokenLine*/);
60077362 return;
60147369 */
60157370 if (offLastIncompleteLine == 0)
60167371 {
6017 memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t));
6018 pLineBuf->cwcBuf += cwcToWrite;
7372 kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t));
7373 pLineBuf->u.Con.cwcBuf += cwcToWrite;
60197374 return;
60207375 }
60217376 }
60227377
60237378 /*
6024 * If there is sufficient combined buffer to handle this request, this are rather simple.
7379 * If there is sufficient combined buffer to handle this request, this is rather simple.
60257380 */
6026 if (pLineBuf->cwcBuf + cchLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
6027 {
6028 if (pLineBuf->cwcBuf > 0)
6029 {
6030 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
6031 pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
6032 pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
6033 pLineBuf->cwcBuf = 0;
6034 }
6035
6036 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
6037 pwcBuffer, offLastIncompleteLine * sizeof(wchar_t));
7381 kHlpAssert(pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf));
7382 if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
7383 {
7384 if (pLineBuf->u.Con.cwcBuf > 0)
7385 {
7386 kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
7387 pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t));
7388 pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf;
7389 pLineBuf->u.Con.cwcBuf = 0;
7390 }
7391
7392 kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
7393 pwcBuffer, offLastIncompleteLine * sizeof(wchar_t));
60387394 pSandbox->Combined.cwcBuf += offLastIncompleteLine;
60397395 }
60407396 else
60467402 KU32 off = 0;
60477403 KU32 offNextLine = 0;
60487404
6049 /* If there is buffered chars, we handle the first line outside the
7405 /* If there are buffered chars, we handle the first line outside the
60507406 main loop. We must try our best outputting it as a complete line. */
6051 if (pLineBuf->cwcBuf > 0)
7407 if (pLineBuf->u.Con.cwcBuf > 0)
60527408 {
60537409 while (offNextLine < cwcToWrite && pwcBuffer[offNextLine] != '\n')
60547410 offNextLine++;
60557411 offNextLine++;
60567412 kHlpAssert(offNextLine <= offLastIncompleteLine);
60577413
6058 if (pLineBuf->cwcBuf + offNextLine + pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf))
7414 if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offNextLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
60597415 {
6060 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
6061 pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
6062 pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
6063 pLineBuf->cwcBuf = 0;
6064
6065 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t));
7416 kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
7417 pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t));
7418 pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf;
7419 pLineBuf->u.Con.cwcBuf = 0;
7420
7421 kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t));
60667422 pSandbox->Combined.cwcBuf += offNextLine;
60677423 }
60687424 else
60697425 {
6070 KU32 cwcLeft = pLineBuf->cwcBufAlloc - pLineBuf->cwcBuf;
7426 KU32 cwcLeft = pLineBuf->u.Con.cwcBufAlloc - pLineBuf->u.Con.cwcBuf;
60717427 if (cwcLeft > 0)
60727428 {
60737429 KU32 cwcCopy = K_MIN(cwcLeft, offNextLine);
6074 memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t));
6075 pLineBuf->cwcBuf += cwcCopy;
7430 kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t));
7431 pLineBuf->u.Con.cwcBuf += cwcCopy;
60767432 off += cwcCopy;
60777433 }
6078 if (pLineBuf->cwcBuf > 0)
7434 if (pLineBuf->u.Con.cwcBuf > 0)
60797435 {
6080 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
6081 pLineBuf->cwcBuf = 0;
7436 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf,
7437 K_TRUE /*fBrokenLine*/);
7438 pLineBuf->u.Con.cwcBuf = 0;
60827439 }
60837440 if (off < offNextLine)
60847441 kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_TRUE /*fBrokenLine*/);
61017458 /*
61027459 * Buffer any remaining incomplete line chars.
61037460 */
6104 if (offLastIncompleteLine < cwcToWrite)
6105 {
6106 memcpy(&pLineBuf->pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t));
6107 pLineBuf->cwcBuf = cchLastIncompleteLine;
7461 if (cchLastIncompleteLine)
7462 {
7463 kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t));
7464 pLineBuf->u.Con.cwcBuf = cchLastIncompleteLine;
61087465 }
61097466 }
61107467 }
61187475 * @param pchBuffer What to write.
61197476 * @param cchToWrite How much to write.
61207477 */
6121 static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite)
7478 static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite)
61227479 {
61237480 /*
61247481 * Convert it to wide char and use the 'W' to do the work.
61277484 KU32 cwcBuf = cchToWrite * 2 + 1;
61287485 wchar_t *pwcBufFree = NULL;
61297486 wchar_t *pwcBuf;
7487 kHlpAssert(pLineBuf->fIsConsole);
61307488
61317489 if (cwcBuf <= 4096)
61327490 pwcBuf = alloca(cwcBuf * sizeof(wchar_t));
61427500 kHlpAssertFailed();
61437501
61447502 /* Flush the line buffer and combined buffer before calling WriteConsoleA. */
6145 if (pLineBuf->cwcBuf > 0)
6146 {
6147 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBroken*/);
6148 pLineBuf->cwcBuf = 0;
7503 if (pLineBuf->u.Con.cwcBuf > 0)
7504 {
7505 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBroken*/);
7506 pLineBuf->u.Con.cwcBuf = 0;
61497507 }
61507508 kwSandboxConsoleFlushCombined(pSandbox);
61517509
61757533 BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cbToWrite, PDWORD pcbWritten,
61767534 PVOID pvReserved)
61777535 {
6178 BOOL fRc;
6179 PKWCONSOLEOUTPUTLINE pLineBuf;
7536 BOOL fRc;
7537 PKWOUTPUTSTREAMBUF pLineBuf;
61807538 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
61817539
61827540 if (hConOutput == g_Sandbox.StdErr.hOutput)
61877545 {
61887546 kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (char const *)pvBuffer, cbToWrite);
61897547
6190 KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
6191 hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
7548 KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
7549 hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
61927550 if (pcbWritten)
61937551 *pcbWritten = cbToWrite;
61947552 fRc = TRUE;
61967554 else
61977555 {
61987556 fRc = WriteConsoleA(hConOutput, pvBuffer, cbToWrite, pcbWritten, pvReserved);
6199 KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
6200 hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
7557 KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
7558 hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
62017559 }
62027560 return fRc;
62037561 }
62077565 BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cwcToWrite, PDWORD pcwcWritten,
62087566 PVOID pvReserved)
62097567 {
6210 BOOL fRc;
6211 PKWCONSOLEOUTPUTLINE pLineBuf;
7568 BOOL fRc;
7569 PKWOUTPUTSTREAMBUF pLineBuf;
62127570 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
62137571
62147572 if (hConOutput == g_Sandbox.StdErr.hOutput)
62157573 pLineBuf = &g_Sandbox.StdErr;
7574 else if (hConOutput == g_Sandbox.StdOut.hOutput)
7575 pLineBuf = &g_Sandbox.StdOut;
62167576 else
6217 pLineBuf = &g_Sandbox.StdOut;
7577 pLineBuf = g_Sandbox.StdErr.fIsConsole ? &g_Sandbox.StdErr : &g_Sandbox.StdOut;
62187578 if (pLineBuf->fIsConsole)
62197579 {
62207580 kwSandboxConsoleWriteW(&g_Sandbox, pLineBuf, (wchar_t const *)pvBuffer, cwcToWrite);
62217581
6222 KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
6223 hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
7582 KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
7583 hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
62247584 if (pcwcWritten)
62257585 *pcwcWritten = cwcToWrite;
62267586 fRc = TRUE;
62287588 else
62297589 {
62307590 fRc = WriteConsoleW(hConOutput, pvBuffer, cwcToWrite, pcwcWritten, pvReserved);
6231 KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
6232 hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
7591 KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
7592 hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
62337593 }
62347594 return fRc;
62357595 }
62467606 *
62477607 */
62487608
6249 /** Kernel32 - VirtualAlloc - for c1[xx].dll 78GB leaks. */
7609 #ifdef WITH_FIXED_VIRTUAL_ALLOCS
7610
7611 /** For debug logging. */
7612 # ifndef NDEBUG
7613 static void kwSandboxLogFixedAllocation(KU32 idxFixed, const char *pszWhere)
7614 {
7615 MEMORY_BASIC_INFORMATION MemInfo = { NULL, NULL, 0, 0, 0, 0, 0};
7616 SIZE_T cbMemInfo = VirtualQuery(g_aFixedVirtualAllocs[idxFixed].pvReserved, &MemInfo, sizeof(MemInfo));
7617 kHlpAssert(cbMemInfo == sizeof(MemInfo));
7618 if (cbMemInfo != 0)
7619 KW_LOG(("%s: #%u %p LB %#x: base=%p alloc=%p region=%#x state=%#x prot=%#x type=%#x\n",
7620 pszWhere, idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed,
7621 MemInfo.BaseAddress,
7622 MemInfo.AllocationBase,
7623 MemInfo.RegionSize,
7624 MemInfo.State,
7625 MemInfo.Protect,
7626 MemInfo.Type));
7627 }
7628 # else
7629 # define kwSandboxLogFixedAllocation(idxFixed, pszWhere) do { } while (0)
7630 # endif
7631
7632 /**
7633 * Used by both kwSandbox_Kernel32_VirtualFree and kwSandboxCleanupLate
7634 *
7635 * @param idxFixed The fixed allocation index to "free".
7636 */
7637 static void kwSandboxResetFixedAllocation(KU32 idxFixed)
7638 {
7639 BOOL fRc;
7640 kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pre]");
7641 fRc = VirtualFree(g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed, MEM_DECOMMIT);
7642 kHlpAssert(fRc); K_NOREF(fRc);
7643 kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pst]");
7644 g_aFixedVirtualAllocs[idxFixed].fInUse = K_FALSE;
7645 }
7646
7647 #endif /* WITH_FIXED_VIRTUAL_ALLOCS */
7648
7649
7650 /** Kernel32 - VirtualAlloc - for managing cl.exe / c1[xx].dll heap with fixed
7651 * location (~78MB in 32-bit 2010 compiler). */
62507652 static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWORD fAllocType, DWORD fProt)
62517653 {
6252 PVOID pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
7654 PVOID pvMem;
7655 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
7656 {
7657 KU32 idxPreAllocated = KU32_MAX;
7658
7659 #ifdef WITH_FIXED_VIRTUAL_ALLOCS
7660 /*
7661 * Look for a pre-reserved CL.exe heap allocation.
7662 */
7663 pvMem = NULL;
7664 if ( pvAddr != 0
7665 && (fAllocType & MEM_RESERVE))
7666 {
7667 KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs);
7668 kHlpAssert(!(fAllocType & ~(MEM_RESERVE | MEM_TOP_DOWN)));
7669 while (idxFixed-- > 0)
7670 if ( g_aFixedVirtualAllocs[idxFixed].uFixed == (KUPTR)pvAddr
7671 && g_aFixedVirtualAllocs[idxFixed].pvReserved)
7672 {
7673 if (g_aFixedVirtualAllocs[idxFixed].cbFixed >= cb)
7674 {
7675 if (!g_aFixedVirtualAllocs[idxFixed].fInUse)
7676 {
7677 g_aFixedVirtualAllocs[idxFixed].fInUse = K_TRUE;
7678 pvMem = pvAddr;
7679 idxPreAllocated = idxFixed;
7680 KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p [pre allocated]\n",
7681 pvAddr, cb, fAllocType, fProt, pvMem));
7682 kwSandboxLogFixedAllocation(idxFixed, "kwSandbox_Kernel32_VirtualAlloc");
7683 SetLastError(NO_ERROR);
7684 break;
7685 }
7686 kwErrPrintf("VirtualAlloc: Fixed allocation at %p is already in use!\n", pvAddr);
7687 }
7688 else
7689 kwErrPrintf("VirtualAlloc: Fixed allocation at %p LB %#x not large enough: %#x\n",
7690 pvAddr, g_aFixedVirtualAllocs[idxFixed].cbFixed, cb);
7691 }
7692 }
7693 if (!pvMem)
7694 #endif
7695 {
7696 pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
7697 KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n",
7698 pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()));
7699 if (pvAddr && pvAddr != pvMem)
7700 kwErrPrintf("VirtualAlloc %p LB %#x (%#x,%#x) failed: %p / %u\n",
7701 pvAddr, cb, fAllocType, fProt, pvMem, GetLastError());
7702 }
7703
7704 if (pvMem)
7705 {
7706 /*
7707 * Track it.
7708 */
7709 PKWVIRTALLOC pTracker;
7710 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
7711
7712 pTracker = g_Sandbox.pVirtualAllocHead;
7713 while ( pTracker
7714 && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc)
7715 pTracker = pTracker->pNext;
7716 if (!pTracker)
7717 {
7718 DWORD dwErr = GetLastError();
7719 PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker));
7720 if (pTracker)
7721 {
7722 pTracker->pvAlloc = pvMem;
7723 pTracker->cbAlloc = cb;
7724 pTracker->idxPreAllocated = idxPreAllocated;
7725 pTracker->pNext = g_Sandbox.pVirtualAllocHead;
7726 g_Sandbox.pVirtualAllocHead = pTracker;
7727 }
7728 SetLastError(dwErr);
7729 }
7730 }
7731 }
7732 else
7733 pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
62537734 KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n",
62547735 pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()));
6255 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
6256 && pvMem)
6257 {
6258 PKWVIRTALLOC pTracker;
6259 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6260
6261 pTracker = g_Sandbox.pVirtualAllocHead;
6262 while ( pTracker
6263 && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc)
6264 pTracker = pTracker->pNext;
6265 if (!pTracker)
6266 {
6267 DWORD dwErr = GetLastError();
6268 PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker));
6269 if (pTracker)
6270 {
6271 pTracker->pvAlloc = pvMem;
6272 pTracker->cbAlloc = cb;
6273 pTracker->pNext = g_Sandbox.pVirtualAllocHead;
6274 g_Sandbox.pVirtualAllocHead = pTracker;
6275 }
6276 SetLastError(dwErr);
6277 }
6278 }
62797736 return pvMem;
62807737 }
62817738
62837740 /** Kernel32 - VirtualFree. */
62847741 static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD dwFreeType)
62857742 {
6286 BOOL fRc = VirtualFree(pvAddr, cb, dwFreeType);
6287 KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
7743 BOOL fRc;
62887744 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
62897745 {
62907746 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
63077763 pPrev->pNext = pTracker->pNext;
63087764 }
63097765 if (pTracker)
6310 kHlpFree(pTracker);
6311 else
6312 KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr));
6313 }
6314 }
6315 }
7766 {
7767 #ifdef WITH_FIXED_VIRTUAL_ALLOCS
7768 if (pTracker->idxPreAllocated != KU32_MAX)
7769 {
7770 kwSandboxResetFixedAllocation(pTracker->idxPreAllocated);
7771 KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> TRUE [pre allocated #%u]\n",
7772 pvAddr, cb, dwFreeType, pTracker->idxPreAllocated));
7773 kHlpFree(pTracker);
7774 return TRUE;
7775 }
7776 #endif
7777
7778 fRc = VirtualFree(pvAddr, cb, dwFreeType);
7779 if (fRc)
7780 kHlpFree(pTracker);
7781 else
7782 {
7783 pTracker->pNext = g_Sandbox.pVirtualAllocHead;
7784 g_Sandbox.pVirtualAllocHead = pTracker;
7785 }
7786 KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
7787 return fRc;
7788 }
7789
7790 KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr));
7791 }
7792 }
7793 }
7794
7795 #ifdef WITH_FIXED_VIRTUAL_ALLOCS
7796 /*
7797 * Protect our fixed allocations (this isn't just paranoia, btw.).
7798 */
7799 if (dwFreeType & MEM_RELEASE)
7800 {
7801 KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs);
7802 while (idxFixed-- > 0)
7803 if (g_aFixedVirtualAllocs[idxFixed].pvReserved == pvAddr)
7804 {
7805 KW_LOG(("VirtualFree: Damn it! Don't free g_aFixedVirtualAllocs[#%u]: %p LB %#x\n",
7806 idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed));
7807 return TRUE;
7808 }
7809 }
7810 #endif
7811
7812 /*
7813 * Not tracker or not actually free the virtual range.
7814 */
7815 fRc = VirtualFree(pvAddr, cb, dwFreeType);
7816 KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
63167817 return fRc;
63177818 }
63187819
63847885 * Thread/Fiber local storage leak prevention.
63857886 * Thread/Fiber local storage leak prevention.
63867887 *
6387 * Note! The FlsAlloc/Free causes problems for statically linked VS2010
6388 * code like VBoxBs3ObjConverter.exe. One thing is that we're
6389 * leaking these indexes, but more importantely we crash during
7888 * Note! The FlsAlloc/Free & TlsAlloc/Free causes problems for statically
7889 * linked VS2010 code like VBoxBs3ObjConverter.exe. One thing is that
7890 * we're leaking these indexes, but more importantely we crash during
63907891 * worker exit since the callback is triggered multiple times.
63917892 */
63927893
64497950 }
64507951
64517952
7953 /** Kernel32 - TlsAlloc */
7954 DWORD WINAPI kwSandbox_Kernel32_TlsAlloc(VOID)
7955 {
7956 DWORD idxTls = TlsAlloc();
7957 KW_LOG(("TlsAlloc() -> %#x\n", idxTls));
7958 if (idxTls != TLS_OUT_OF_INDEXES)
7959 {
7960 PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker));
7961 if (pTracker)
7962 {
7963 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
7964 pTracker->idx = idxTls;
7965 pTracker->pNext = g_Sandbox.pTlsAllocHead;
7966 g_Sandbox.pTlsAllocHead = pTracker;
7967 }
7968 }
7969
7970 return idxTls;
7971 }
7972
7973 /** Kernel32 - TlsFree */
7974 BOOL WINAPI kwSandbox_Kernel32_TlsFree(DWORD idxTls)
7975 {
7976 BOOL fRc = TlsFree(idxTls);
7977 KW_LOG(("TlsFree(%#x) -> %d\n", idxTls, fRc));
7978 if (fRc)
7979 {
7980 PKWLOCALSTORAGE pTracker;
7981 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
7982
7983 pTracker = g_Sandbox.pTlsAllocHead;
7984 if (pTracker)
7985 {
7986 if (pTracker->idx == idxTls)
7987 g_Sandbox.pTlsAllocHead = pTracker->pNext;
7988 else
7989 {
7990 PKWLOCALSTORAGE pPrev;
7991 do
7992 {
7993 pPrev = pTracker;
7994 pTracker = pTracker->pNext;
7995 } while (pTracker && pTracker->idx != idxTls);
7996 if (pTracker)
7997 pPrev->pNext = pTracker->pNext;
7998 }
7999 if (pTracker)
8000 {
8001 pTracker->idx = TLS_OUT_OF_INDEXES;
8002 pTracker->pNext = NULL;
8003 kHlpFree(pTracker);
8004 }
8005 }
8006 }
8007 return fRc;
8008 }
8009
8010
64528011
64538012 /*
64548013 *
64648023
64658024 #ifdef WITH_HASH_MD5_CACHE
64668025
6467 /** Advapi32 - CryptCreateHash */
8026 /** AdvApi32 - CryptCreateHash */
64688027 static BOOL WINAPI kwSandbox_Advapi32_CryptCreateHash(HCRYPTPROV hProv, ALG_ID idAlg, HCRYPTKEY hKey, DWORD dwFlags,
64698028 HCRYPTHASH *phHash)
64708029 {
65238082 }
65248083
65258084
6526 /** Advapi32 - CryptHashData */
8085 /** AdvApi32 - CryptHashData */
65278086 static BOOL WINAPI kwSandbox_Advapi32_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD cbData, DWORD dwFlags)
65288087 {
65298088 BOOL fRc;
66388197 }
66398198
66408199
6641 /** Advapi32 - CryptGetHashParam */
8200 /** AdvApi32 - CryptGetHashParam */
66428201 static BOOL WINAPI kwSandbox_Advapi32_CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam,
66438202 BYTE *pbData, DWORD *pcbData, DWORD dwFlags)
66448203 {
67968355 }
67978356
67988357
6799 /** Advapi32 - CryptDestroyHash */
8358 /** AdvApi32 - CryptDestroyHash */
68008359 static BOOL WINAPI kwSandbox_Advapi32_CryptDestroyHash(HCRYPTHASH hHash)
68018360 {
68028361 BOOL fRc;
68418400 }
68428401
68438402 #endif /* WITH_HASH_MD5_CACHE */
8403
8404
8405 /*
8406 *
8407 * Reuse crypt context.
8408 * Reuse crypt context.
8409 * Reuse crypt context.
8410 *
8411 *
8412 * This saves a little bit of time and registry accesses each time CL, C1 or C1XX runs.
8413 *
8414 */
8415
8416 #ifdef WITH_CRYPT_CTX_REUSE
8417
8418 /** AdvApi32 - CryptAcquireContextW. */
8419 static BOOL WINAPI kwSandbox_Advapi32_CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider,
8420 DWORD dwProvType, DWORD dwFlags)
8421 {
8422 BOOL fRet;
8423
8424 /*
8425 * Lookup reusable context based on the input.
8426 */
8427 KSIZE const cwcContainer = pwszContainer ? kwUtf16Len(pwszContainer) : 0;
8428 KSIZE const cwcProvider = pwszProvider ? kwUtf16Len(pwszProvider) : 0;
8429 KU32 iCtx = g_Sandbox.cCryptCtxs;
8430 while (iCtx-- > 0)
8431 {
8432 if ( g_Sandbox.aCryptCtxs[iCtx].cwcContainer == cwcContainer
8433 && g_Sandbox.aCryptCtxs[iCtx].cwcProvider == cwcProvider
8434 && g_Sandbox.aCryptCtxs[iCtx].dwProvType == dwProvType
8435 && g_Sandbox.aCryptCtxs[iCtx].dwFlags == dwFlags
8436 && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszContainer, pwszContainer, cwcContainer * sizeof(wchar_t)) == 0
8437 && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszProvider, pwszProvider, cwcProvider * sizeof(wchar_t)) == 0)
8438 {
8439 if (CryptContextAddRef(g_Sandbox.aCryptCtxs[iCtx].hProv, NULL, 0))
8440 {
8441 *phProv = g_Sandbox.aCryptCtxs[iCtx].hProv;
8442 KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [reused]\n",
8443 pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv));
8444 return TRUE;
8445 }
8446 }
8447 }
8448
8449 /*
8450 * Create it and enter it into the reused array if possible.
8451 */
8452 fRet = CryptAcquireContextW(phProv, pwszContainer, pwszProvider, dwProvType, dwFlags);
8453 if (fRet)
8454 {
8455 iCtx = g_Sandbox.cCryptCtxs;
8456 if (iCtx < K_ELEMENTS(g_Sandbox.aCryptCtxs))
8457 {
8458 /* Try duplicate the input strings. */
8459 g_Sandbox.aCryptCtxs[iCtx].pwszContainer = kHlpDup(pwszContainer ? pwszContainer : L"",
8460 (cwcContainer + 1) * sizeof(wchar_t));
8461 if (g_Sandbox.aCryptCtxs[iCtx].pwszContainer)
8462 {
8463 g_Sandbox.aCryptCtxs[iCtx].pwszProvider = kHlpDup(pwszProvider ? pwszProvider : L"",
8464 (cwcProvider + 1) * sizeof(wchar_t));
8465 if (g_Sandbox.aCryptCtxs[iCtx].pwszProvider)
8466 {
8467 /* Add a couple of references just to be on the safe side and all that. */
8468 HCRYPTPROV hProv = *phProv;
8469 if (CryptContextAddRef(hProv, NULL, 0))
8470 {
8471 if (CryptContextAddRef(hProv, NULL, 0))
8472 {
8473 /* Okay, finish the entry and return success */
8474 g_Sandbox.aCryptCtxs[iCtx].hProv = hProv;
8475 g_Sandbox.aCryptCtxs[iCtx].dwProvType = dwProvType;
8476 g_Sandbox.aCryptCtxs[iCtx].dwFlags = dwFlags;
8477 g_Sandbox.cCryptCtxs = iCtx + 1;
8478
8479 KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [new]\n",
8480 pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv));
8481 return TRUE;
8482 }
8483 CryptReleaseContext(hProv, 0);
8484 }
8485 KWCRYPT_LOG(("CryptAcquireContextW: CryptContextAddRef failed!\n"));
8486
8487 kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszProvider);
8488 g_Sandbox.aCryptCtxs[iCtx].pwszProvider = NULL;
8489 }
8490 kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszContainer);
8491 g_Sandbox.aCryptCtxs[iCtx].pwszContainer = NULL;
8492 }
8493 }
8494 else
8495 KWCRYPT_LOG(("CryptAcquireContextW: Too many crypt contexts to keep and reuse!\n"));
8496 }
8497
8498 KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> %d, %p\n",
8499 pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv));
8500 return fRet;
8501 }
8502
8503
8504 /** AdvApi32 - CryptReleaseContext */
8505 static BOOL WINAPI kwSandbox_Advapi32_CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
8506 {
8507 BOOL fRet = CryptReleaseContext(hProv, dwFlags);
8508 KWCRYPT_LOG(("CryptReleaseContext(%p,%#x) -> %d\n", hProv, dwFlags, fRet));
8509 return fRet;
8510 }
8511
8512
8513 /** AdvApi32 - CryptContextAddRef */
8514 static BOOL WINAPI kwSandbox_Advapi32_CryptContextAddRef(HCRYPTPROV hProv, DWORD *pdwReserved, DWORD dwFlags)
8515 {
8516 BOOL fRet = CryptContextAddRef(hProv, pdwReserved, dwFlags);
8517 KWCRYPT_LOG(("CryptContextAddRef(%p,%p,%#x) -> %d\n", hProv, pdwReserved, dwFlags, fRet));
8518 return fRet;
8519 }
8520
8521 #endif /* WITH_CRYPT_CTX_REUSE */
8522
8523 /*
8524 *
8525 * Structured exception handling.
8526 * Structured exception handling.
8527 * Structured exception handling.
8528 *
8529 */
8530 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
8531
8532 # define EH_NONCONTINUABLE KU32_C(0x00000001)
8533 # define EH_UNWINDING KU32_C(0x00000002)
8534 # define EH_EXIT_UNWIND KU32_C(0x00000004)
8535 # define EH_STACK_INVALID KU32_C(0x00000008)
8536 # define EH_NESTED_CALL KU32_C(0x00000010)
8537
8538 typedef KU32 (__cdecl * volatile PFNXCPTHANDLER)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT,
8539 struct _EXCEPTION_REGISTRATION_RECORD * volatile *);
8540 typedef struct _EXCEPTION_REGISTRATION_RECORD
8541 {
8542 struct _EXCEPTION_REGISTRATION_RECORD * volatile pPrevRegRec;
8543 PFNXCPTHANDLER pfnXcptHandler;
8544 };
8545
8546
8547 /**
8548 * Calls @a pfnHandler.
8549 */
8550 static KU32 kwSandboxXcptCallHandler(PEXCEPTION_RECORD pXcptRec, struct _EXCEPTION_REGISTRATION_RECORD *pRegRec,
8551 PCONTEXT pXcptCtx, struct _EXCEPTION_REGISTRATION_RECORD * volatile * ppRegRec,
8552 PFNXCPTHANDLER pfnHandler)
8553 {
8554 # if 1
8555 /* This is a more robust version that isn't subject to calling
8556 convension cleanup disputes and such. */
8557 KU32 uSavedEdi;
8558 KU32 uSavedEsi;
8559 KU32 uSavedEbx;
8560 KU32 rcHandler;
8561
8562 __asm
8563 {
8564 mov [uSavedEdi], edi
8565 mov [uSavedEsi], esi
8566 mov [uSavedEbx], ebx
8567 mov esi, esp
8568 mov edi, esp
8569 mov edi, [pXcptRec]
8570 mov edx, [pRegRec]
8571 mov eax, [pXcptCtx]
8572 mov ebx, [ppRegRec]
8573 mov ecx, [pfnHandler]
8574 sub esp, 16
8575 and esp, 0fffffff0h
8576 mov [esp ], edi
8577 mov [esp + 4], edx
8578 mov [esp + 8], eax
8579 mov [esp + 12], ebx
8580 mov edi, esi
8581 call ecx
8582 mov esp, esi
8583 cmp esp, edi
8584 je stack_ok
8585 int 3
8586 stack_ok:
8587 mov edi, [uSavedEdi]
8588 mov esi, [uSavedEsi]
8589 mov ebx, [uSavedEbx]
8590 mov [rcHandler], eax
8591 }
8592 return rcHandler;
8593 # else
8594 return pfnHandler(pXcptRec, pRegRec, pXctpCtx, ppRegRec);
8595 # endif
8596 }
8597
8598
8599 /**
8600 * Vectored exception handler that emulates x86 chained exception handler.
8601 *
8602 * This is necessary because the RtlIsValidHandler check fails for self loaded
8603 * code and prevents cl.exe from working. (On AMD64 we can register function
8604 * tables, but on X86 cooking your own handling seems to be the only viabke
8605 * alternative.)
8606 *
8607 * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION.
8608 * @param pXcptPtrs The exception details.
8609 */
8610 static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs)
8611 {
8612 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
8613 KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode));
8614 if (g_Sandbox.fRunning)
8615 {
8616 HANDLE const hCurProc = GetCurrentProcess();
8617 PEXCEPTION_RECORD pXcptRec = pXcptPtrs->ExceptionRecord;
8618 PCONTEXT pXcptCtx = pXcptPtrs->ContextRecord;
8619 struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = pTib->ExceptionList;
8620 while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL)
8621 {
8622 /* Read the exception record in a safe manner. */
8623 struct _EXCEPTION_REGISTRATION_RECORD RegRec;
8624 DWORD cbActuallyRead = 0;
8625 if ( ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead)
8626 && cbActuallyRead == sizeof(RegRec))
8627 {
8628 struct _EXCEPTION_REGISTRATION_RECORD * volatile pDispRegRec = NULL;
8629 KU32 rcHandler;
8630 KW_LOG(("kwSandboxVecXcptEmulateChained: calling %p, pRegRec=%p, pPrevRegRec=%p\n",
8631 RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec));
8632 rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler);
8633 KW_LOG(("kwSandboxVecXcptEmulateChained: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec));
8634 if (rcHandler == ExceptionContinueExecution)
8635 {
8636 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE));
8637 KW_LOG(("kwSandboxVecXcptEmulateChained: returning EXCEPTION_CONTINUE_EXECUTION!\n"));
8638 return EXCEPTION_CONTINUE_EXECUTION;
8639 }
8640
8641 if (rcHandler == ExceptionContinueSearch)
8642 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
8643 else if (rcHandler == ExceptionNestedException)
8644 kHlpAssertMsgFailed(("Nested exceptions.\n"));
8645 else
8646 kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
8647 }
8648 else
8649 {
8650 KW_LOG(("kwSandboxVecXcptEmulateChained: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec));
8651 break;
8652 }
8653
8654 /*
8655 * Next.
8656 */
8657 pRegRec = RegRec.pPrevRegRec;
8658 }
8659 }
8660 return EXCEPTION_CONTINUE_SEARCH;
8661 }
8662
8663
8664 /** NtDll,Kernel32 - RtlUnwind */
8665 static VOID WINAPI kwSandbox_ntdll_RtlUnwind(struct _EXCEPTION_REGISTRATION_RECORD *pStopXcptRec, PVOID pvTargetIp,
8666 PEXCEPTION_RECORD pXcptRec, PVOID pvReturnValue)
8667 {
8668 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
8669 KW_LOG(("kwSandbox_ntdll_RtlUnwind: pStopXcptRec=%p pvTargetIp=%p pXctpRec=%p pvReturnValue=%p%s\n",
8670 pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue, g_Sandbox.fRunning ? "" : " [sandbox not running]"));
8671 if (g_Sandbox.fRunning)
8672 {
8673 HANDLE const hCurProc = GetCurrentProcess();
8674 PCONTEXT pXcptCtx = NULL;
8675 struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = pTib->ExceptionList;
8676
8677 /*
8678 * Update / create an exception record.
8679 */
8680 if (pXcptRec)
8681 pXcptRec->ExceptionFlags |= EH_UNWINDING;
8682 else
8683 {
8684 pXcptRec = (PEXCEPTION_RECORD)alloca(sizeof(*pXcptRec));
8685 kHlpMemSet(pXcptRec, 0, sizeof(*pXcptRec));
8686 pXcptRec->ExceptionCode = STATUS_UNWIND;
8687 pXcptRec->ExceptionFlags = EH_UNWINDING;
8688 }
8689 if (!pStopXcptRec)
8690 pXcptRec->ExceptionFlags |= EH_EXIT_UNWIND;
8691
8692 /*
8693 * Walk the chain till we find pStopXctpRec.
8694 */
8695 while ( ((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0
8696 && pRegRec != NULL
8697 && pRegRec != pStopXcptRec)
8698 {
8699 /* Read the exception record in a safe manner. */
8700 struct _EXCEPTION_REGISTRATION_RECORD RegRec;
8701 DWORD cbActuallyRead = 0;
8702 if ( ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead)
8703 && cbActuallyRead == sizeof(RegRec))
8704 {
8705 struct _EXCEPTION_REGISTRATION_RECORD * volatile pDispRegRec = NULL;
8706 KU32 rcHandler;
8707 KW_LOG(("kwSandbox_ntdll_RtlUnwind: calling %p, pRegRec=%p, pPrevRegRec=%p\n",
8708 RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec));
8709 rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler);
8710 KW_LOG(("kwSandbox_ntdll_RtlUnwind: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec));
8711
8712 if (rcHandler == ExceptionContinueSearch)
8713 kHlpAssert(!(pXcptRec->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
8714 else if (rcHandler == ExceptionCollidedUnwind)
8715 kHlpAssertMsgFailed(("Implement collided unwind!\n"));
8716 else
8717 kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
8718 }
8719 else
8720 {
8721 KW_LOG(("kwSandbox_ntdll_RtlUnwind: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec));
8722 break;
8723 }
8724
8725 /*
8726 * Pop next.
8727 */
8728 pTib->ExceptionList = RegRec.pPrevRegRec;
8729 pRegRec = RegRec.pPrevRegRec;
8730 }
8731 return;
8732 }
8733
8734 RtlUnwind(pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue);
8735 }
8736
8737 #endif /* WINDOWS + X86 */
68448738
68458739
68468740 /*
69238817 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
69248818 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
69258819 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
8820 { TUPLE("MapViewOfFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx },
69268821 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
69278822 #endif
69288823 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
69298824 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
8825 { TUPLE("DuplicateHandle"), NULL, (KUPTR)kwSandbox_Kernel32_DuplicateHandle },
69308826 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
69318827 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
69328828 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
69448840 { TUPLE("HeapCreate"), NULL, (KUPTR)kwSandbox_Kernel32_HeapCreate, K_TRUE /*fOnlyExe*/ },
69458841 { TUPLE("HeapDestroy"), NULL, (KUPTR)kwSandbox_Kernel32_HeapDestroy, K_TRUE /*fOnlyExe*/ },
69468842
6947 { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc },
6948 { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree },
8843 { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc, K_TRUE /*fOnlyExe*/ },
8844 { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree, K_TRUE /*fOnlyExe*/ },
8845 { TUPLE("TlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_TlsAlloc, K_TRUE /*fOnlyExe*/ },
8846 { TUPLE("TlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_TlsFree, K_TRUE /*fOnlyExe*/ },
69498847
69508848 { TUPLE("SetConsoleCtrlHandler"), NULL, (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler },
8849
8850 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
8851 { TUPLE("RtlUnwind"), NULL, (KUPTR)kwSandbox_ntdll_RtlUnwind },
8852 #endif
69518853
69528854 #ifdef WITH_HASH_MD5_CACHE
69538855 { TUPLE("CryptCreateHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptCreateHash },
69548856 { TUPLE("CryptHashData"), NULL, (KUPTR)kwSandbox_Advapi32_CryptHashData },
69558857 { TUPLE("CryptGetHashParam"), NULL, (KUPTR)kwSandbox_Advapi32_CryptGetHashParam },
69568858 { TUPLE("CryptDestroyHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptDestroyHash },
8859 #endif
8860
8861 #ifdef WITH_CRYPT_CTX_REUSE
8862 { TUPLE("CryptAcquireContextW"), NULL, (KUPTR)kwSandbox_Advapi32_CryptAcquireContextW },
8863 { TUPLE("CryptReleaseContext"), NULL, (KUPTR)kwSandbox_Advapi32_CryptReleaseContext },
8864 { TUPLE("CryptContextAddRef"), NULL, (KUPTR)kwSandbox_Advapi32_CryptContextAddRef },
69578865 #endif
69588866
69598867 /*
70468954 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
70478955 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
70488956 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
8957 { TUPLE("MapViewOfFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx },
70498958 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
70508959 #endif
70518960 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
70528961 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
8962 { TUPLE("DuplicateHandle"), NULL, (KUPTR)kwSandbox_Kernel32_DuplicateHandle },
70538963 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
70548964 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
70558965 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
70718981
70728982 { TUPLE("RtlPcToFileHeader"), NULL, (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader },
70738983
8984 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
8985 { TUPLE("RtlUnwind"), NULL, (KUPTR)kwSandbox_ntdll_RtlUnwind },
8986 #endif
70748987
70758988 /*
70768989 * MS Visual C++ CRTs.
70929005
70939006
70949007 /**
9008 * Functions that needs replacing when queried by GetProcAddress.
9009 */
9010 KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[] =
9011 {
9012 /*
9013 * Kernel32.dll and friends.
9014 */
9015 { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc, K_TRUE /*fOnlyExe*/ },
9016 { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree, K_TRUE /*fOnlyExe*/ },
9017 { TUPLE("TlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_TlsAlloc, K_TRUE /*fOnlyExe*/ },
9018 { TUPLE("TlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_TlsFree, K_TRUE /*fOnlyExe*/ },
9019 };
9020 /** Number of entries in g_aSandboxGetProcReplacements. */
9021 KU32 const g_cSandboxGetProcReplacements = K_ELEMENTS(g_aSandboxGetProcReplacements);
9022
9023
9024 /**
70959025 * Control handler.
70969026 *
70979027 * @returns TRUE if handled, FALSE if not.
71039033 {
71049034 case CTRL_C_EVENT:
71059035 fprintf(stderr, "kWorker: Ctrl-C\n");
9036 g_fCtrlC = K_TRUE;
71069037 exit(9);
71079038 break;
71089039
71099040 case CTRL_BREAK_EVENT:
71109041 fprintf(stderr, "kWorker: Ctrl-Break\n");
9042 g_fCtrlC = K_TRUE;
71119043 exit(10);
71129044 break;
71139045
71149046 case CTRL_CLOSE_EVENT:
71159047 fprintf(stderr, "kWorker: console closed\n");
9048 g_fCtrlC = K_TRUE;
71169049 exit(11);
71179050 break;
71189051
71199052 case CTRL_LOGOFF_EVENT:
71209053 fprintf(stderr, "kWorker: logoff event\n");
9054 g_fCtrlC = K_TRUE;
71219055 exit(11);
71229056 break;
71239057
71249058 case CTRL_SHUTDOWN_EVENT:
71259059 fprintf(stderr, "kWorker: shutdown event\n");
9060 g_fCtrlC = K_TRUE;
71269061 exit(11);
71279062 break;
71289063
71669101 }
71679102
71689103
7169 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
7170 typedef struct _EXCEPTION_REGISTRATION_RECORD
7171 {
7172 struct _EXCEPTION_REGISTRATION_RECORD * volatile PrevStructure;
7173 KU32 (__cdecl * volatile ExceptionHandler)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT,
7174 struct _EXCEPTION_REGISTRATION_RECORD * volatile *);
7175 };
7176
7177 /**
7178 * Vectored exception handler that emulates x86 chained exception handler.
7179 *
7180 * This is necessary because the RtlIsValidHandler check fails for self loaded
7181 * code and prevents cl.exe from working. (On AMD64 we can register function
7182 * tables, but on X86 cooking your own handling seems to be the only viabke
7183 * alternative.)
7184 *
7185 * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION.
7186 * @param pXcptPtrs The exception details.
7187 */
7188 static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs)
7189 {
7190 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
7191 KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode));
7192 if (g_Sandbox.fRunning)
7193 {
7194 PEXCEPTION_RECORD pXcptRec = pXcptPtrs->ExceptionRecord;
7195 PCONTEXT pXcptCtx = pXcptPtrs->ContextRecord;
7196 struct _EXCEPTION_REGISTRATION_RECORD * volatile *ppRegRec = &pTib->ExceptionList;
7197 struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = *ppRegRec;
7198 while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL)
7199 {
7200 #if 1
7201 /* This is a more robust version that isn't subject to calling
7202 convension cleanup disputes and such. */
7203 KU32 uSavedEdi;
7204 KU32 uSavedEsi;
7205 KU32 uSavedEbx;
7206 KU32 rcHandler;
7207 __asm
7208 {
7209 mov [uSavedEdi], edi
7210 mov [uSavedEsi], esi
7211 mov [uSavedEbx], ebx
7212 mov esi, esp
7213 mov edi, esp
7214 mov ecx, [pXcptRec]
7215 mov edx, [pRegRec]
7216 mov eax, [pXcptCtx]
7217 mov ebx, [ppRegRec]
7218 sub esp, 16
7219 and esp, 0fffffff0h
7220 mov [esp ], ecx
7221 mov [esp + 4], edx
7222 mov [esp + 8], eax
7223 mov [esp + 12], ebx
7224 call dword ptr [edx + 4]
7225 mov esp, esi
7226 cmp esp, edi
7227 je stack_ok
7228 int 3
7229 stack_ok:
7230 mov edi, [uSavedEdi]
7231 mov esi, [uSavedEsi]
7232 mov ebx, [uSavedEbx]
7233 mov [rcHandler], eax
7234 }
7235 #else
7236 KU32 rcHandler = pRegRec->ExceptionHandler(pXcptPtrs->ExceptionRecord, pRegRec, pXcptPtrs->ContextRecord, ppRegRec);
7237 #endif
7238 if (rcHandler == ExceptionContinueExecution)
7239 {
7240 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE));
7241 return EXCEPTION_CONTINUE_EXECUTION;
7242 }
7243 if (rcHandler == ExceptionContinueSearch)
7244 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
7245 else if (rcHandler == ExceptionNestedException)
7246 kHlpAssertMsgFailed(("Nested exceptions.\n"));
7247 else
7248 kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
7249
7250 /*
7251 * Next.
7252 */
7253 ppRegRec = &pRegRec->PrevStructure;
7254 pRegRec = pRegRec->PrevStructure;
7255 }
7256 }
7257 return EXCEPTION_CONTINUE_SEARCH;
7258 }
7259 #endif /* WINDOWS + X86 */
7260
7261
72629104 /**
72639105 * Enters the given handle into the handle table.
72649106 *
72659107 * @returns K_TRUE on success, K_FALSE on failure.
72669108 * @param pSandbox The sandbox.
72679109 * @param pHandle The handle.
7268 */
7269 static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle)
7270 {
7271 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(pHandle->hHandle);
9110 * @param hHandle The handle value to enter it under (for the
9111 * duplicate handle API).
9112 */
9113 static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle)
9114 {
9115 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hHandle);
72729116 kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE);
72739117
72749118 /*
73589202
73599203 static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
73609204 KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
7361 KU32 cEnvVars, const char **papszEnvVars)
9205 KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching)
73629206 {
73639207 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
9208 PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
73649209 wchar_t *pwcPool;
73659210 KSIZE cbStrings;
73669211 KSIZE cwc;
73679212 KSIZE cbCmdLine;
73689213 KU32 i;
7369 int rc;
73709214
73719215 /* Simple stuff. */
73729216 pSandbox->rcExitCode = 256;
73759219 pSandbox->pgmptr = (char *)pTool->pszPath;
73769220 pSandbox->wpgmptr = (wchar_t *)pTool->pwszPath;
73779221 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
7378 pSandbox->StdOut.cwcBuf = 0;
7379 pSandbox->StdErr.cwcBuf = 0;
7380 pSandbox->Combined.cwcBuf = 0;
9222 if (pSandbox->StdOut.fIsConsole)
9223 pSandbox->StdOut.u.Con.cwcBuf = 0;
9224 else
9225 pSandbox->StdOut.u.Fully.cchBuf = 0;
9226 if (pSandbox->StdErr.fIsConsole)
9227 pSandbox->StdErr.u.Con.cwcBuf = 0;
9228 else
9229 pSandbox->StdErr.u.Fully.cchBuf = 0;
9230 pSandbox->Combined.cwcBuf = 0;
73819231 pSandbox->Combined.cFlushes = 0;
73829232 #endif
9233 pSandbox->fNoPchCaching = fNoPchCaching;
73839234 pSandbox->cArgs = cArgs;
73849235 pSandbox->papszArgs = (char **)papszArgs;
73859236 pSandbox->pszCmdLine = kwSandboxInitCmdLineFromArgv(cArgs, papszArgs, fWatcomBrainDamange, &cbCmdLine);
74139264 return KERR_NO_MEMORY;
74149265 cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
74159266
7416 pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
7417 pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
7418 pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
9267 pSandbox->SavedCommandLine = pProcParams->CommandLine;
9268 pProcParams->CommandLine.Buffer = pSandbox->pwszCmdLine;
9269 pProcParams->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
74199270
74209271 /*
7421 * Setup the enviornment.
9272 * Setup the environment.
74229273 */
7423 rc = kwSandboxGrowEnv(pSandbox, cEnvVars + 2);
7424 if (rc == 0)
9274 if ( cEnvVars + 2 <= pSandbox->cEnvVarsAllocated
9275 || kwSandboxGrowEnv(pSandbox, cEnvVars + 2) == 0)
74259276 {
74269277 KU32 iDst = 0;
74279278 for (i = 0; i < cEnvVars; i++)
74579308 pSandbox->wenviron[iDst] = NULL;
74589309 }
74599310 else
7460 return kwErrPrintfRc(KERR_NO_MEMORY, "Error setting up environment variables: %d\n", rc);
9311 return kwErrPrintfRc(KERR_NO_MEMORY, "Error setting up environment variables: kwSandboxGrowEnv failed\n");
9312
74619313
74629314 /*
74639315 * Invalidate the volatile parts of cache (kBuild output directory,
74649316 * temporary directory, whatever).
74659317 */
74669318 kFsCacheInvalidateCustomBoth(g_pFsCache);
9319
9320 #ifdef WITH_HISTORY
9321 /*
9322 * Record command line in debug history.
9323 */
9324 kHlpFree(g_apszHistory[g_iHistoryNext]);
9325 g_apszHistory[g_iHistoryNext] = kHlpStrDup(pSandbox->pszCmdLine);
9326 g_iHistoryNext = (g_iHistoryNext + 1) % K_ELEMENTS(g_apszHistory);
9327 #endif
9328
74679329 return 0;
74689330 }
74699331
74909352 #endif
74919353 PKWEXITCALLACK pExitCallback;
74929354
9355 /*
9356 * First stuff that may cause code to run.
9357 */
9358
74939359 /* Do exit callback first. */
74949360 pExitCallback = g_Sandbox.pExitCallbackHead;
74959361 g_Sandbox.pExitCallbackHead = NULL;
75129378 pExitCallback = pNext;
75139379 }
75149380
9381 /* Free left behind FlsAlloc leaks. */
9382 pLocalStorage = g_Sandbox.pFlsAllocHead;
9383 g_Sandbox.pFlsAllocHead = NULL;
9384 while (pLocalStorage)
9385 {
9386 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
9387 KW_LOG(("Freeing leaked FlsAlloc index %#x\n", pLocalStorage->idx));
9388 FlsFree(pLocalStorage->idx);
9389 kHlpFree(pLocalStorage);
9390 pLocalStorage = pNext;
9391 }
9392
9393 /* Free left behind TlsAlloc leaks. */
9394 pLocalStorage = g_Sandbox.pTlsAllocHead;
9395 g_Sandbox.pTlsAllocHead = NULL;
9396 while (pLocalStorage)
9397 {
9398 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
9399 KW_LOG(("Freeing leaked TlsAlloc index %#x\n", pLocalStorage->idx));
9400 TlsFree(pLocalStorage->idx);
9401 kHlpFree(pLocalStorage);
9402 pLocalStorage = pNext;
9403 }
9404
9405
9406 /*
9407 * Then free resources associated with the sandbox run.
9408 */
9409
9410 /* Open handles, except fixed handles (stdout and stderr). */
9411 if (pSandbox->cActiveHandles > pSandbox->cFixedHandles)
9412 {
9413 KU32 idxHandle = pSandbox->cHandles;
9414 while (idxHandle-- > 0)
9415 if (pSandbox->papHandles[idxHandle] == NULL)
9416 { /* likely */ }
9417 else
9418 {
9419 PKWHANDLE pHandle = pSandbox->papHandles[idxHandle];
9420 if ( pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF
9421 || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle) )
9422 {
9423 pSandbox->papHandles[idxHandle] = NULL;
9424 pSandbox->cLeakedHandles++;
9425
9426 switch (pHandle->enmType)
9427 {
9428 case KWHANDLETYPE_FSOBJ_READ_CACHE:
9429 KWFS_LOG(("Closing leaked read cache handle: %#x/%p cRefs=%d\n",
9430 idxHandle, pHandle->hHandle, pHandle->cRefs));
9431 break;
9432 case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING:
9433 KWFS_LOG(("Closing leaked read mapping handle: %#x/%p cRefs=%d\n",
9434 idxHandle, pHandle->hHandle, pHandle->cRefs));
9435 break;
9436 case KWHANDLETYPE_OUTPUT_BUF:
9437 KWFS_LOG(("Closing leaked output buf handle: %#x/%p cRefs=%d\n",
9438 idxHandle, pHandle->hHandle, pHandle->cRefs));
9439 break;
9440 case KWHANDLETYPE_TEMP_FILE:
9441 KWFS_LOG(("Closing leaked temp file handle: %#x/%p cRefs=%d\n",
9442 idxHandle, pHandle->hHandle, pHandle->cRefs));
9443 pHandle->u.pTempFile->cActiveHandles--;
9444 break;
9445 case KWHANDLETYPE_TEMP_FILE_MAPPING:
9446 KWFS_LOG(("Closing leaked temp mapping handle: %#x/%p cRefs=%d\n",
9447 idxHandle, pHandle->hHandle, pHandle->cRefs));
9448 pHandle->u.pTempFile->cActiveHandles--;
9449 break;
9450 default:
9451 kHlpAssertFailed();
9452 }
9453 if (--pHandle->cRefs == 0)
9454 kHlpFree(pHandle);
9455 if (--pSandbox->cActiveHandles == pSandbox->cFixedHandles)
9456 break;
9457 }
9458 }
9459 kHlpAssert(pSandbox->cActiveHandles == pSandbox->cFixedHandles);
9460 }
9461
9462 /* Reset memory mappings - This assumes none of the DLLs keeps any of our mappings open! */
9463 g_Sandbox.cMemMappings = 0;
75159464
75169465 #ifdef WITH_TEMP_MEMORY_FILES
75179466 /* The temporary files aren't externally visible, they're all in memory. */
75319480 }
75329481 #endif
75339482
9483 /* Free left behind HeapCreate leaks. */
9484 pHeap = g_Sandbox.pHeapHead;
9485 g_Sandbox.pHeapHead = NULL;
9486 while (pHeap != NULL)
9487 {
9488 PKWHEAP pNext = pHeap->pNext;
9489 KW_LOG(("Freeing HeapCreate leak %p\n", pHeap->hHeap));
9490 HeapDestroy(pHeap->hHeap);
9491 pHeap = pNext;
9492 }
9493
75349494 /* Free left behind VirtualAlloc leaks. */
75359495 pTracker = g_Sandbox.pVirtualAllocHead;
75369496 g_Sandbox.pVirtualAllocHead = NULL;
75389498 {
75399499 PKWVIRTALLOC pNext = pTracker->pNext;
75409500 KW_LOG(("Freeing VirtualFree leak %p LB %#x\n", pTracker->pvAlloc, pTracker->cbAlloc));
7541 VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE);
9501
9502 #ifdef WITH_FIXED_VIRTUAL_ALLOCS
9503 if (pTracker->idxPreAllocated != KU32_MAX)
9504 kwSandboxResetFixedAllocation(pTracker->idxPreAllocated);
9505 else
9506 #endif
9507 VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE);
75429508 kHlpFree(pTracker);
75439509 pTracker = pNext;
75449510 }
7545
7546 /* Free left behind HeapCreate leaks. */
7547 pHeap = g_Sandbox.pHeapHead;
7548 g_Sandbox.pHeapHead = NULL;
7549 while (pHeap != NULL)
7550 {
7551 PKWHEAP pNext = pHeap->pNext;
7552 KW_LOG(("Freeing HeapCreate leak %p\n", pHeap->hHeap));
7553 HeapDestroy(pHeap->hHeap);
7554 pHeap = pNext;
7555 }
7556
7557 /* Free left behind FlsAlloc leaks. */
7558 pLocalStorage = g_Sandbox.pFlsAllocHead;
7559 g_Sandbox.pFlsAllocHead = NULL;
7560 while (pLocalStorage)
7561 {
7562 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
7563 KW_LOG(("Freeing leaked FlsAlloc index %#x\n", pLocalStorage->idx));
7564 FlsFree(pLocalStorage->idx);
7565 kHlpFree(pLocalStorage);
7566 pLocalStorage = pNext;
7567 }
7568
7569 /* Free left behind TlsAlloc leaks. */
7570 pLocalStorage = g_Sandbox.pTlsAllocHead;
7571 g_Sandbox.pTlsAllocHead = NULL;
7572 while (pLocalStorage)
7573 {
7574 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
7575 KW_LOG(("Freeing leaked TlsAlloc index %#x\n", pLocalStorage->idx));
7576 TlsFree(pLocalStorage->idx);
7577 kHlpFree(pLocalStorage);
7578 pLocalStorage = pNext;
7579 }
7580
75819511
75829512 /* Free the environment. */
75839513 if (pSandbox->papszEnvVars)
76169546 MemInfo.WorkingSetSize = 0;
76179547 if (GetProcessMemoryInfo(GetCurrentProcess(), &MemInfo, sizeof(MemInfo)))
76189548 {
9549 /* The first time thru, we figure out approximately when to restart
9550 based on installed RAM and CPU threads. */
9551 static KU64 s_cbMaxWorkingSet = 0;
9552 if (s_cbMaxWorkingSet != 0)
9553 { /* likely */ }
9554 else
9555 {
9556 SYSTEM_INFO SysInfo;
9557 MEMORYSTATUSEX GlobalMemInfo;
9558 const char *pszValue;
9559
9560 /* Calculate a reasonable estimate. */
9561 kHlpMemSet(&SysInfo, 0, sizeof(SysInfo));
9562 GetNativeSystemInfo(&SysInfo);
9563
9564 kHlpMemSet(&GlobalMemInfo, 0, sizeof(GlobalMemInfo));
9565 GlobalMemInfo.dwLength = sizeof(GlobalMemInfo);
9566 if (!GlobalMemoryStatusEx(&GlobalMemInfo))
76199567 #if K_ARCH_BITS >= 64
7620 if (MemInfo.WorkingSetSize >= 512*1024*1024)
9568 GlobalMemInfo.ullTotalPhys = KU64_C(0x000200000000); /* 8GB */
76219569 #else
7622 if (MemInfo.WorkingSetSize >= 384*1024*1024)
9570 GlobalMemInfo.ullTotalPhys = KU64_C(0x000080000000); /* 2GB */
76239571 #endif
9572 s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys / (K_MAX(SysInfo.dwNumberOfProcessors, 1) * 4);
9573 KW_LOG(("Raw estimate of s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet));
9574
9575 /* User limit. */
9576 pszValue = getenv("KWORKER_MEMORY_LIMIT");
9577 if (pszValue != NULL)
9578 {
9579 char *pszNext;
9580 unsigned long ulValue = strtol(pszValue, &pszNext, 0);
9581 if (*pszNext == '\0' || *pszNext == 'M')
9582 s_cbMaxWorkingSet = ulValue * (KU64)1048576;
9583 else if (*pszNext == 'K')
9584 s_cbMaxWorkingSet = ulValue * (KU64)1024;
9585 else if (*pszNext == 'G')
9586 s_cbMaxWorkingSet = ulValue * (KU64)1073741824;
9587 else
9588 kwErrPrintf("Unable to grok KWORKER_MEMORY_LIMIT: %s\n", pszValue);
9589 KW_LOG(("User s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet));
9590 }
9591
9592 /* Clamp it a little. */
9593 if (s_cbMaxWorkingSet < 168*1024*1024)
9594 s_cbMaxWorkingSet = 168*1024*1024;
9595 #if K_ARCH_BITS < 64
9596 else
9597 s_cbMaxWorkingSet = K_MIN(s_cbMaxWorkingSet,
9598 SysInfo.dwProcessorType != PROCESSOR_ARCHITECTURE_AMD64
9599 ? 512*1024*1024 /* Only got 2 or 3 GB VA */
9600 : 1536*1024*1024 /* got 4GB VA */);
9601 #endif
9602 if (s_cbMaxWorkingSet > GlobalMemInfo.ullTotalPhys)
9603 s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys;
9604 KW_LOG(("Final s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet));
9605 }
9606
9607 /* Finally the check. */
9608 if (MemInfo.WorkingSetSize >= s_cbMaxWorkingSet)
76249609 {
76259610 KW_LOG(("WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize));
7626 //fprintf(stderr, "WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize);
76279611 g_fRestart = K_TRUE;
76289612 }
76299613 }
7630 }
7631
7632
9614
9615 /*
9616 * The CRT has a max of 8192 handles, so we better restart after a while if
9617 * someone is leaking handles or we risk running out of descriptors.
9618 *
9619 * Note! We only detect leaks for handles we intercept. In the case of CL.EXE
9620 * doing _dup2(1, 2) (stderr ==> stdout), there isn't actually a leak.
9621 */
9622 if (pSandbox->cLeakedHandles > 6000)
9623 {
9624 KW_LOG(("LeakedHandles = %#x - > restart next time.\n", pSandbox->cLeakedHandles));
9625 g_fRestart = K_TRUE;
9626 }
9627 }
9628
9629
9630 /**
9631 * Does essential cleanups and restoring, anything externally visible.
9632 *
9633 * All cleanups that aren't externally visible are postponed till after we've
9634 * informed kmk of the result, so it can be done in the dead time between jobs.
9635 *
9636 * @param pSandbox The sandbox.
9637 */
76339638 static void kwSandboxCleanup(PKWSANDBOX pSandbox)
76349639 {
76359640 /*
76369641 * Restore the parent command line string.
76379642 */
76389643 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
7639 pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
7640
7641 /*
7642 * Kill all open handles.
7643 */
7644 if (pSandbox->cActiveHandles > 0)
7645 {
7646 KU32 i = pSandbox->cHandles;
7647 while (i-- > 0)
7648 if (pSandbox->papHandles[i] == NULL)
7649 { /* likely */ }
7650 else
7651 {
7652 PKWHANDLE pHandle = pSandbox->papHandles[i];
7653 pSandbox->papHandles[i] = NULL;
7654 switch (pHandle->enmType)
7655 {
7656 case KWHANDLETYPE_FSOBJ_READ_CACHE:
7657 break;
7658 case KWHANDLETYPE_TEMP_FILE:
7659 case KWHANDLETYPE_TEMP_FILE_MAPPING:
7660 pHandle->u.pTempFile->cActiveHandles--;
7661 break;
7662 default:
7663 kHlpAssertFailed();
7664 }
7665 kHlpFree(pHandle);
7666 if (--pSandbox->cActiveHandles == 0)
7667 break;
7668 }
7669 }
9644 PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
9645 pProcParams->CommandLine = pSandbox->SavedCommandLine;
9646 pProcParams->StandardOutput = pSandbox->StdOut.hOutput;
9647 pProcParams->StandardError = pSandbox->StdErr.hOutput; /* CL.EXE messes with this one. */
76709648 }
76719649
76729650
76739651 static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
7674 KU32 cEnvVars, const char **papszEnvVars)
9652 KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching)
76759653 {
76769654 int rcExit = 42;
76779655 int rc;
76799657 /*
76809658 * Initialize the sandbox environment.
76819659 */
7682 rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
9660 rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching);
76839661 if (rc == 0)
76849662 {
76859663 /*
77409718 #endif
77419719 __except (EXCEPTION_EXECUTE_HANDLER)
77429720 {
9721 kwErrPrintf("Caught exception %#x!\n", GetExceptionCode());
9722 #ifdef WITH_HISTORY
9723 {
9724 KU32 cPrinted = 0;
9725 while (cPrinted++ < 5)
9726 {
9727 KU32 idx = (g_iHistoryNext + K_ELEMENTS(g_apszHistory) - cPrinted) % K_ELEMENTS(g_apszHistory);
9728 if (g_apszHistory[idx])
9729 kwErrPrintf("cmd[%d]: %s\n", 1 - cPrinted, g_apszHistory[idx]);
9730 }
9731 }
9732 #endif
77439733 rcExit = 512;
77449734 }
77459735 pSandbox->fRunning = K_FALSE;
78009790 * @param papszArgs The argument vector.
78019791 * @param fWatcomBrainDamange Whether to apply watcom rules while quoting.
78029792 * @param cEnvVars The number of environment variables.
7803 * @param papszEnvVars The enviornment vector.
9793 * @param papszEnvVars The environment vector.
9794 * @param fNoPchCaching Whether to disable precompiled header file
9795 * caching. Avoid trouble when creating them.
78049796 * @param cPostCmdArgs Number of post command arguments (includes cmd).
78059797 * @param papszPostCmdArgs The post command and its argument.
78069798 */
78079799 static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
78089800 KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
7809 KU32 cEnvVars, const char **papszEnvVars,
9801 KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching,
78109802 KU32 cPostCmdArgs, const char **papszPostCmdArgs)
78119803 {
78129804 int rcExit;
78139805 PKWTOOL pTool;
9806
9807 KW_LOG(("\n\nkSubmitHandleJobUnpacked: '%s' in '%s' cArgs=%u cEnvVars=%u cPostCmdArgs=%u\n",
9808 pszExecutable, pszCwd, cArgs, cEnvVars, cPostCmdArgs));
9809 #ifdef KW_LOG_ENABLED
9810 {
9811 KU32 i;
9812 for (i = 0; i < cArgs; i++)
9813 KW_LOG((" papszArgs[%u]=%s\n", i, papszArgs[i]));
9814 for (i = 0; i < cPostCmdArgs; i++)
9815 KW_LOG((" papszPostCmdArgs[%u]=%s\n", i, papszPostCmdArgs[i]));
9816 }
9817 #endif
9818 g_cJobs++;
78149819
78159820 /*
78169821 * Lookup the tool.
78509855 if (pTool->enmType == KWTOOLTYPE_SANDBOXED)
78519856 {
78529857 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
7853 rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
9858 rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange,
9859 cEnvVars, papszEnvVars, fNoPchCaching);
78549860 }
78559861 else
78569862 {
79849990 }
79859991 papszEnvVars[cEnvVars] = 0;
79869992
7987 /* Flags (currently just watcom argument brain damanage). */
7988 if (cbMsg >= sizeof(KU8))
9993 /* Flags (currently just watcom argument brain damage and no precompiled header caching). */
9994 if (cbMsg >= sizeof(KU8) * 2)
79899995 {
79909996 KBOOL fWatcomBrainDamange = *pszMsg++;
7991 cbMsg--;
9997 KBOOL fNoPchCaching = *pszMsg++;
9998 cbMsg -= 2;
79929999
799310000 /* Post command argument count (can be zero). */
799410001 if (cbMsg >= sizeof(KU32))
802410031 */
802510032 rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
802610033 cArgs, papszArgs, fWatcomBrainDamange,
8027 cEnvVars, papszEnvVars,
10034 cEnvVars, papszEnvVars, fNoPchCaching,
802810035 cPostCmdArgs, apszPostCmdArgs);
802910036 }
803010037 else if (cbMsg == KSIZE_MAX)
814910156
815010157
815110158 /**
10159 * Decimal formatting of a 64-bit unsigned value into a large enough buffer.
10160 *
10161 * @returns pszBuf
10162 * @param pszBuf The buffer (sufficiently large).
10163 * @param uValue The value.
10164 */
10165 static const char *kwFmtU64(char *pszBuf, KU64 uValue)
10166 {
10167 char szTmp[64];
10168 char *psz = &szTmp[63];
10169 int cch = 4;
10170
10171 *psz-- = '\0';
10172 do
10173 {
10174 if (--cch == 0)
10175 {
10176 *psz-- = ' ';
10177 cch = 3;
10178 }
10179 *psz-- = (uValue % 10) + '0';
10180 uValue /= 10;
10181 } while (uValue != 0);
10182
10183 return strcpy(pszBuf, psz + 1);
10184 }
10185
10186
10187 /**
10188 * Prints statistics.
10189 */
10190 static void kwPrintStats(void)
10191 {
10192 PROCESS_MEMORY_COUNTERS_EX MemInfo;
10193 MEMORYSTATUSEX MemStatus;
10194 IO_COUNTERS IoCounters;
10195 DWORD cHandles;
10196 KSIZE cMisses;
10197 char szBuf[16*1024];
10198 int off = 0;
10199 char szPrf[24];
10200 char sz1[64];
10201 char sz2[64];
10202 char sz3[64];
10203 char sz4[64];
10204 extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile);
10205
10206 sprintf(szPrf, "%5d/%u:", getpid(), K_ARCH_BITS);
10207
10208 szBuf[off++] = '\n';
10209
10210 off += sprintf(&szBuf[off], "%s %14s jobs, %s tools, %s modules, %s non-native ones\n", szPrf,
10211 kwFmtU64(sz1, g_cJobs), kwFmtU64(sz2, g_cTools), kwFmtU64(sz3, g_cModules), kwFmtU64(sz4, g_cNonNativeModules));
10212 off += sprintf(&szBuf[off], "%s %14s bytes in %s read-cached files, avg %s bytes\n", szPrf,
10213 kwFmtU64(sz1, g_cbReadCachedFiles), kwFmtU64(sz2, g_cReadCachedFiles),
10214 kwFmtU64(sz3, g_cbReadCachedFiles / K_MAX(g_cReadCachedFiles, 1)));
10215
10216 off += sprintf(&szBuf[off], "%s %14s bytes read in %s calls\n",
10217 szPrf, kwFmtU64(sz1, g_cbReadFileTotal), kwFmtU64(sz2, g_cReadFileCalls));
10218
10219 off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from read cached files\n", szPrf,
10220 kwFmtU64(sz1, g_cbReadFileFromReadCached), (unsigned)(g_cbReadFileFromReadCached * (KU64)100 / g_cbReadFileTotal),
10221 kwFmtU64(sz2, g_cReadFileFromReadCached), (unsigned)(g_cReadFileFromReadCached * (KU64)100 / g_cReadFileCalls));
10222
10223 off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from in-memory temporary files\n", szPrf,
10224 kwFmtU64(sz1, g_cbReadFileFromInMemTemp), (unsigned)(g_cbReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cbReadFileTotal, 1)),
10225 kwFmtU64(sz2, g_cReadFileFromInMemTemp), (unsigned)(g_cReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cReadFileCalls, 1)));
10226
10227 off += sprintf(&szBuf[off], "%s %14s bytes written in %s calls\n", szPrf,
10228 kwFmtU64(sz1, g_cbWriteFileTotal), kwFmtU64(sz2, g_cWriteFileCalls));
10229 off += sprintf(&szBuf[off], "%s %14s bytes written (%u%%) in %s calls (%u%%) to in-memory temporary files\n", szPrf,
10230 kwFmtU64(sz1, g_cbWriteFileToInMemTemp),
10231 (unsigned)(g_cbWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cbWriteFileTotal, 1)),
10232 kwFmtU64(sz2, g_cWriteFileToInMemTemp),
10233 (unsigned)(g_cWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cWriteFileCalls, 1)));
10234
10235 off += sprintf(&szBuf[off], "%s %14s bytes for the cache\n", szPrf,
10236 kwFmtU64(sz1, g_pFsCache->cbObjects + g_pFsCache->cbAnsiPaths + g_pFsCache->cbUtf16Paths + sizeof(*g_pFsCache)));
10237 off += sprintf(&szBuf[off], "%s %14s objects, taking up %s bytes, avg %s bytes\n", szPrf,
10238 kwFmtU64(sz1, g_pFsCache->cObjects),
10239 kwFmtU64(sz2, g_pFsCache->cbObjects),
10240 kwFmtU64(sz3, g_pFsCache->cbObjects / g_pFsCache->cObjects));
10241 off += sprintf(&szBuf[off], "%s %14s A path hashes, taking up %s bytes, avg %s bytes, %s collision\n", szPrf,
10242 kwFmtU64(sz1, g_pFsCache->cAnsiPaths),
10243 kwFmtU64(sz2, g_pFsCache->cbAnsiPaths),
10244 kwFmtU64(sz3, g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1)),
10245 kwFmtU64(sz4, g_pFsCache->cAnsiPathCollisions));
10246 #ifdef KFSCACHE_CFG_UTF16
10247 off += sprintf(&szBuf[off], "%s %14s W path hashes, taking up %s bytes, avg %s bytes, %s collisions\n", szPrf,
10248 kwFmtU64(sz1, g_pFsCache->cUtf16Paths),
10249 kwFmtU64(sz2, g_pFsCache->cbUtf16Paths),
10250 kwFmtU64(sz3, g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1)),
10251 kwFmtU64(sz4, g_pFsCache->cUtf16PathCollisions));
10252 #endif
10253 off += sprintf(&szBuf[off], "%s %14s child hash tables, total of %s entries, %s children inserted, %s collisions\n", szPrf,
10254 kwFmtU64(sz1, g_pFsCache->cChildHashTabs),
10255 kwFmtU64(sz2, g_pFsCache->cChildHashEntriesTotal),
10256 kwFmtU64(sz3, g_pFsCache->cChildHashed),
10257 kwFmtU64(sz4, g_pFsCache->cChildHashCollisions));
10258
10259 cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits;
10260 off += sprintf(&szBuf[off], "%s %14s lookups: %s (%u%%) path hash hits, %s (%u%%) walks hits, %s (%u%%) misses\n", szPrf,
10261 kwFmtU64(sz1, g_pFsCache->cLookups),
10262 kwFmtU64(sz2, g_pFsCache->cPathHashHits),
10263 (unsigned)(g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)),
10264 kwFmtU64(sz3, g_pFsCache->cWalkHits),
10265 (unsigned)(g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)),
10266 kwFmtU64(sz4, cMisses),
10267 (unsigned)(cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)));
10268
10269 off += sprintf(&szBuf[off], "%s %14s child searches, %s (%u%%) hash hits\n", szPrf,
10270 kwFmtU64(sz1, g_pFsCache->cChildSearches),
10271 kwFmtU64(sz2, g_pFsCache->cChildHashHits),
10272 (unsigned)(g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1)));
10273 off += sprintf(&szBuf[off], "%s %14s name changes, growing %s times (%u%%)\n", szPrf,
10274 kwFmtU64(sz1, g_pFsCache->cNameChanges),
10275 kwFmtU64(sz2, g_pFsCache->cNameGrowths),
10276 (unsigned)(g_pFsCache->cNameGrowths * 100 / K_MAX(g_pFsCache->cNameChanges, 1)) );
10277
10278
10279 /*
10280 * Process & Memory details.
10281 */
10282 if (!GetProcessHandleCount(GetCurrentProcess(), &cHandles))
10283 cHandles = 0;
10284 MemInfo.cb = sizeof(MemInfo);
10285 if (!GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&MemInfo, sizeof(MemInfo)))
10286 memset(&MemInfo, 0, sizeof(MemInfo));
10287 off += sprintf(&szBuf[off], "%s %14s handles; %s page faults; %s bytes page file, peaking at %s bytes\n", szPrf,
10288 kwFmtU64(sz1, cHandles),
10289 kwFmtU64(sz2, MemInfo.PageFaultCount),
10290 kwFmtU64(sz3, MemInfo.PagefileUsage),
10291 kwFmtU64(sz4, MemInfo.PeakPagefileUsage));
10292 off += sprintf(&szBuf[off], "%s %14s bytes working set, peaking at %s bytes; %s byte private\n", szPrf,
10293 kwFmtU64(sz1, MemInfo.WorkingSetSize),
10294 kwFmtU64(sz2, MemInfo.PeakWorkingSetSize),
10295 kwFmtU64(sz3, MemInfo.PrivateUsage));
10296 off += sprintf(&szBuf[off], "%s %14s bytes non-paged pool, peaking at %s bytes; %s bytes paged pool, peaking at %s bytes\n",
10297 szPrf,
10298 kwFmtU64(sz1, MemInfo.QuotaNonPagedPoolUsage),
10299 kwFmtU64(sz2, MemInfo.QuotaPeakNonPagedPoolUsage),
10300 kwFmtU64(sz3, MemInfo.QuotaPagedPoolUsage),
10301 kwFmtU64(sz4, MemInfo.QuotaPeakPagedPoolUsage));
10302
10303 if (!GetProcessIoCounters(GetCurrentProcess(), &IoCounters))
10304 memset(&IoCounters, 0, sizeof(IoCounters));
10305 off += sprintf(&szBuf[off], "%s %14s bytes in %s reads [src: OS]\n", szPrf,
10306 kwFmtU64(sz1, IoCounters.ReadTransferCount),
10307 kwFmtU64(sz2, IoCounters.ReadOperationCount));
10308 off += sprintf(&szBuf[off], "%s %14s bytes in %s writes [src: OS]\n", szPrf,
10309 kwFmtU64(sz1, IoCounters.WriteTransferCount),
10310 kwFmtU64(sz2, IoCounters.WriteOperationCount));
10311 off += sprintf(&szBuf[off], "%s %14s bytes in %s other I/O operations [src: OS]\n", szPrf,
10312 kwFmtU64(sz1, IoCounters.OtherTransferCount),
10313 kwFmtU64(sz2, IoCounters.OtherOperationCount));
10314
10315 MemStatus.dwLength = sizeof(MemStatus);
10316 if (!GlobalMemoryStatusEx(&MemStatus))
10317 memset(&MemStatus, 0, sizeof(MemStatus));
10318 off += sprintf(&szBuf[off], "%s %14s bytes used VA, %#" KX64_PRI " bytes available\n", szPrf,
10319 kwFmtU64(sz1, MemStatus.ullTotalVirtual - MemStatus.ullAvailVirtual),
10320 MemStatus.ullAvailVirtual);
10321 off += sprintf(&szBuf[off], "%s %14u %% system memory load\n", szPrf, MemStatus.dwMemoryLoad);
10322
10323 maybe_con_fwrite(szBuf, off, 1, stdout);
10324 fflush(stdout);
10325 }
10326
10327
10328 /**
815210329 * Handles what comes after --test.
815310330 *
815410331 * @returns Exit code.
816510342 const char *pszCwd = getcwd(szCwd, sizeof(szCwd));
816610343 KU32 cEnvVars;
816710344 KBOOL fWatcomBrainDamange = K_FALSE;
10345 KBOOL fNoPchCaching = K_FALSE;
816810346
816910347 /*
817010348 * Parse arguments.
818210360
818310361 /* Optional directory change. */
818410362 if ( i < argc
8185 && strcmp(argv[i], "--chdir") == 0)
10363 && ( strcmp(argv[i], "--chdir") == 0
10364 || strcmp(argv[i], "-C") == 0 ) )
818610365 {
818710366 i++;
818810367 if (i >= argc)
819610375 || strcmp(argv[i], "--watcom-brain-damage") == 0) )
819710376 {
819810377 fWatcomBrainDamange = K_TRUE;
10378 i++;
10379 }
10380
10381 /* Optional watcom flag directory change. */
10382 if ( i < argc
10383 && strcmp(argv[i], "--no-pch-caching") == 0)
10384 {
10385 fNoPchCaching = K_TRUE;
10386 i++;
10387 }
10388
10389 /* Trigger breakpoint */
10390 if ( i < argc
10391 && strcmp(argv[i], "--breakpoint") == 0)
10392 {
10393 __debugbreak();
819910394 i++;
820010395 }
820110396
822510420 {
822610421 rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd,
822710422 argc - i, &argv[i], fWatcomBrainDamange,
8228 cEnvVars, environ,
10423 cEnvVars, environ, fNoPchCaching,
822910424 0, NULL);
823010425 KW_LOG(("rcExit=%d\n", rcExit));
823110426 kwSandboxCleanupLate(&g_Sandbox);
823210427 }
823310428
10429 if (getenv("KWORKER_STATS") != NULL)
10430 kwPrintStats();
10431
10432 # ifdef WITH_LOG_FILE
10433 if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
10434 CloseHandle(g_hLogFile);
10435 # endif
823410436 return rcExit;
823510437 }
823610438
8237 #if 1
823810439
823910440 int main(int argc, char **argv)
824010441 {
8241 KSIZE cbMsgBuf = 0;
8242 KU8 *pbMsgBuf = NULL;
8243 int i;
8244 HANDLE hPipe = INVALID_HANDLE_VALUE;
8245 const char *pszTmp;
8246 KFSLOOKUPERROR enmIgnored;
10442 KSIZE cbMsgBuf = 0;
10443 KU8 *pbMsgBuf = NULL;
10444 int i;
10445 HANDLE hPipe = INVALID_HANDLE_VALUE;
10446 const char *pszTmp;
10447 KFSLOOKUPERROR enmIgnored;
824710448 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
8248 PVOID pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained);
10449 PVOID pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/,
10450 kwSandboxVecXcptEmulateChained);
824910451 #endif
825010452 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
825110453 HANDLE hCurProc = GetCurrentProcess();
825210454 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
825310455 PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
10456 DWORD dwType;
10457 #endif
10458
10459
10460 #ifdef WITH_FIXED_VIRTUAL_ALLOCS
10461 /*
10462 * Reserve memory for cl.exe
10463 */
10464 for (i = 0; i < K_ELEMENTS(g_aFixedVirtualAllocs); i++)
10465 {
10466 g_aFixedVirtualAllocs[i].fInUse = K_FALSE;
10467 g_aFixedVirtualAllocs[i].pvReserved = VirtualAlloc((void *)g_aFixedVirtualAllocs[i].uFixed,
10468 g_aFixedVirtualAllocs[i].cbFixed,
10469 MEM_RESERVE, PAGE_READWRITE);
10470 if ( !g_aFixedVirtualAllocs[i].pvReserved
10471 || g_aFixedVirtualAllocs[i].pvReserved != (void *)g_aFixedVirtualAllocs[i].uFixed)
10472 {
10473 kwErrPrintf("Failed to reserve %p LB %#x: %u\n", g_aFixedVirtualAllocs[i].uFixed, g_aFixedVirtualAllocs[i].cbFixed,
10474 GetLastError());
10475 if (g_aFixedVirtualAllocs[i].pvReserved)
10476 {
10477 VirtualFree(g_aFixedVirtualAllocs[i].pvReserved, g_aFixedVirtualAllocs[i].cbFixed, MEM_RELEASE);
10478 g_aFixedVirtualAllocs[i].pvReserved = NULL;
10479 }
10480 }
10481 }
825410482 #endif
825510483
825610484 /*
827610504 if (pszTmp && *pszTmp != '\0')
827710505 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
827810506
10507 /*
10508 * Make g_abDefLdBuf executable.
10509 */
10510 if (!VirtualProtect(g_abDefLdBuf, sizeof(g_abDefLdBuf), PAGE_EXECUTE_READWRITE, &dwType))
10511 return kwErrPrintfRc(3, "VirtualProtect(%p, %#x, PAGE_EXECUTE_READWRITE,NULL) failed: %u\n",
10512 g_abDefLdBuf, sizeof(g_abDefLdBuf), GetLastError());
10513
827910514 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
828010515 /*
828110516 * Get and duplicate the console handles.
828210517 */
10518 /* Standard output. */
828310519 g_Sandbox.StdOut.hOutput = pProcessParams->StandardOutput;
828410520 if (!DuplicateHandle(hCurProc, pProcessParams->StandardOutput, hCurProc, &g_Sandbox.StdOut.hBackup,
828510521 GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
828610522 kHlpAssertFailedStmt(g_Sandbox.StdOut.hBackup = pProcessParams->StandardOutput);
8287 g_Sandbox.StdOut.fIsConsole = GetFileType(g_Sandbox.StdOut.hOutput) == FILE_TYPE_CHAR;
8288
10523 dwType = GetFileType(g_Sandbox.StdOut.hOutput);
10524 g_Sandbox.StdOut.fIsConsole = dwType == FILE_TYPE_CHAR;
10525 g_Sandbox.StdOut.fFileType = (dwType & ~FILE_TYPE_REMOTE) < 0xf
10526 ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX;
10527 g_Sandbox.HandleStdOut.enmType = KWHANDLETYPE_OUTPUT_BUF;
10528 g_Sandbox.HandleStdOut.cRefs = 0x10001;
10529 g_Sandbox.HandleStdOut.dwDesiredAccess = GENERIC_WRITE;
10530 g_Sandbox.HandleStdOut.u.pOutBuf = &g_Sandbox.StdOut;
10531 g_Sandbox.HandleStdOut.hHandle = g_Sandbox.StdOut.hOutput;
10532 if (g_Sandbox.StdOut.hOutput != INVALID_HANDLE_VALUE)
10533 {
10534 if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdOut, g_Sandbox.StdOut.hOutput))
10535 g_Sandbox.cFixedHandles++;
10536 else
10537 return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdOut (%p)!\n", g_Sandbox.StdOut.hOutput);
10538 }
10539 KWOUT_LOG(("StdOut: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n",
10540 g_Sandbox.StdOut.hOutput, g_Sandbox.StdOut.hBackup, g_Sandbox.StdOut.fIsConsole, dwType));
10541
10542 /* Standard error. */
828910543 g_Sandbox.StdErr.hOutput = pProcessParams->StandardError;
829010544 if (!DuplicateHandle(hCurProc, pProcessParams->StandardError, hCurProc, &g_Sandbox.StdErr.hBackup,
829110545 GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
829210546 kHlpAssertFailedStmt(g_Sandbox.StdErr.hBackup = pProcessParams->StandardError);
8293 g_Sandbox.StdErr.fIsConsole = GetFileType(g_Sandbox.StdErr.hOutput) == FILE_TYPE_CHAR;
8294
10547 dwType = GetFileType(g_Sandbox.StdErr.hOutput);
10548 g_Sandbox.StdErr.fIsConsole = dwType == FILE_TYPE_CHAR;
10549 g_Sandbox.StdErr.fFileType = (dwType & ~FILE_TYPE_REMOTE) < 0xf
10550 ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX;
10551 g_Sandbox.HandleStdErr.enmType = KWHANDLETYPE_OUTPUT_BUF;
10552 g_Sandbox.HandleStdErr.cRefs = 0x10001;
10553 g_Sandbox.HandleStdErr.dwDesiredAccess = GENERIC_WRITE;
10554 g_Sandbox.HandleStdErr.u.pOutBuf = &g_Sandbox.StdErr;
10555 g_Sandbox.HandleStdErr.hHandle = g_Sandbox.StdErr.hOutput;
10556 if ( g_Sandbox.StdErr.hOutput != INVALID_HANDLE_VALUE
10557 && g_Sandbox.StdErr.hOutput != g_Sandbox.StdOut.hOutput)
10558 {
10559 if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdErr, g_Sandbox.StdErr.hOutput))
10560 g_Sandbox.cFixedHandles++;
10561 else
10562 return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdErr (%p)!\n", g_Sandbox.StdErr.hOutput);
10563 }
10564 KWOUT_LOG(("StdErr: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n",
10565 g_Sandbox.StdErr.hOutput, g_Sandbox.StdErr.hBackup, g_Sandbox.StdErr.fIsConsole, dwType));
10566
10567 /* Combined console buffer. */
829510568 if (g_Sandbox.StdErr.fIsConsole)
829610569 {
829710570 g_Sandbox.Combined.hOutput = g_Sandbox.StdErr.hBackup;
830710580 g_Sandbox.Combined.hOutput = INVALID_HANDLE_VALUE;
830810581 g_Sandbox.Combined.uCodepage = CP_ACP;
830910582 }
8310 #endif
10583 KWOUT_LOG(("Combined: hOutput=%p uCodepage=%d\n", g_Sandbox.Combined.hOutput, g_Sandbox.Combined.uCodepage));
10584 #endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
831110585
831210586
831310587 /*
835210626 printf("usage: kWorker [--volatile dir] --pipe <pipe-handle>\n"
835310627 "usage: kWorker <--help|-h>\n"
835410628 "usage: kWorker <--version|-V>\n"
8355 "usage: kWorker [--volatile dir] --test [<times> [--chdir <dir>]] -- args\n"
10629 "usage: kWorker [--volatile dir] --test [<times> [--chdir <dir>] [--breakpoint] -- args\n"
835610630 "\n"
835710631 "This is an internal kmk program that is used via the builtin_kSubmit.\n");
835810632 return 0;
845010724 }
845110725
845210726 CloseHandle(hPipe);
10727 #ifdef WITH_LOG_FILE
10728 if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
10729 CloseHandle(g_hLogFile);
10730 #endif
10731 if (getenv("KWORKER_STATS") != NULL)
10732 kwPrintStats();
845310733 return rc > 0 ? 0 : 1;
845410734 }
845510735 }
845610736
8457 #else
8458
8459 static int kwExecCmdLine(const char *pszExe, const char *pszCmdLine)
8460 {
8461 int rc;
8462 PKWTOOL pTool = kwToolLookup(pszExe);
8463 if (pTool)
8464 {
8465 int rcExitCode;
8466 switch (pTool->enmType)
8467 {
8468 case KWTOOLTYPE_SANDBOXED:
8469 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
8470 rc = kwSandboxExec(&g_Sandbox, pTool, pszCmdLine, &rcExitCode);
8471 break;
8472 default:
8473 kHlpAssertFailed();
8474 KW_LOG(("TODO: Direct exec tool %s\n", pTool->pszPath));
8475 rc = rcExitCode = 2;
8476 break;
8477 }
8478 KW_LOG(("rcExitCode=%d (rc=%d)\n", rcExitCode, rc));
8479 }
8480 else
8481 rc = 1;
8482 return rc;
8483 }
8484
8485 int main(int argc, char **argv)
8486 {
8487 int rc = 0;
8488 int i;
8489 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/v10sp1/atlmfc/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp";
8490 # if 0
8491 rc = kwExecCmdLine(argv[1], argv[2]);
8492 rc = kwExecCmdLine(argv[1], argv[2]);
8493 K_NOREF(i);
8494 # else
8495 // Skylake (W10/amd64, only stdandard MS defender):
8496 // cmd 1: 48 /1024 = 0x0 (0.046875) [for /l %i in (1,1,1024) do ...]
8497 // kmk 1: 44 /1024 = 0x0 (0.04296875) [all: ; 1024 x cl.exe]
8498 // run 1: 37 /1024 = 0x0 (0.0361328125) [just process creation gain]
8499 // run 2: 34 /1024 = 0x0 (0.033203125) [get file attribs]
8500 // run 3: 32.77 /1024 = 0x0 (0.032001953125) [read caching of headers]
8501 // run 4: 32.67 /1024 = 0x0 (0.031904296875) [loader tweaking]
8502 // run 5: 29.144/1024 = 0x0 (0.0284609375) [with temp files in memory]
8503 // r2881 building src/VBox/Runtime:
8504 // without: 2m01.016388s = 120.016388 s
8505 // with: 1m15.165069s = 75.165069 s => 120.016388s - 75.165069s = 44.851319s => 44.85/120.02 = 37% speed up.
8506 // r2884 building vbox/debug (r110512):
8507 // without: 11m14.446609s = 674.446609 s
8508 // with: 9m01.017344s = 541.017344 s => 674.446609s - 541.017344s = 133.429265 => 133.43/674.45 = 19% speed up
8509 // r2896 building vbox/debug (r110577):
8510 // with: 8m31.182384s = 511.182384 s => 674.446609s - 511.182384s = 163.264225 = 163.26/674.45 = 24% speed up
8511 //
8512 // Dell (W7/amd64, infected by mcafee):
8513 // kmk 1: 285.278/1024 = 0x0 (0.278591796875)
8514 // run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
8515 // run 2: 78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
8516 g_cVerbose = 0;
8517 for (i = 0; i < 1024 && rc == 0; i++)
8518 rc = kwExecCmdLine(argv[1], argv[2]);
8519 # endif
8520 return rc;
8521 }
8522
8523 #endif
8524
10737
10738 /** @page pg_kWorker kSubmit / kWorker
10739 *
10740 * @section sec_kWorker_Motivation Motivation / Inspiration
10741 *
10742 * The kSubmit / kWorker combo was conceived as a way to speed up VirtualBox
10743 * builds on machines "infested" by Anti Virus protection and disk encryption
10744 * software. Build times jumping from 35-40 min to 77-82 min after the machine
10745 * got "infected".
10746 *
10747 * Speeing up builting of Boot Sector Kit \#3 was also hightly desirable. It is
10748 * mainly a bunch of tiny assembly and C files being compiler a million times.
10749 * As some of us OS/2 users maybe recalls, the Watcom make program can run its
10750 * own toolchain from within the same process, saving a lot of process creation
10751 * and teardown overhead.
10752 *
10753 *
10754 * @section sec_kWorker_kSubmit About kSubmit
10755 *
10756 * When wanting to execute a job in a kWorker instance, it must be submitted
10757 * using the kmk_builtin_kSubmit command in kmk. As the name suggest, this is
10758 * built into kmk and does not exist as an external program. The reason for
10759 * this is that it keep track of the kWorker instances.
10760 *
10761 * The kSubmit command has the --32-bit and --64-bit options for selecting
10762 * between 32-bit and 64-bit worker instance. We generally assume the user of
10763 * the command knows which bit count the executable has, so kSubmit is spared
10764 * the extra work of finding out.
10765 *
10766 * The kSubmit command shares a environment and current directory manipulation
10767 * with the kRedirect command, but not the file redirection. So long no file
10768 * operation is involed, kSubmit is a drop in kRedirect replacement. This is
10769 * hand for tools like OpenWatcom, NASM and YASM which all require environment
10770 * and/or current directory changes to work.
10771 *
10772 * Unlike the kRedirect command, the kSubmit command can also specify an
10773 * internall post command to be executed after the main command succeeds.
10774 * Currently only kmk_builtin_kDepObj is supported. kDepObj gathers dependency
10775 * information from Microsoft COFF object files and Watcom OMF object files and
10776 * is scheduled to replace kDepIDB.
10777 *
10778 *
10779 * @section sec_kWorker_Interaction kSubmit / kWorker interaction
10780 *
10781 * The kmk_builtin_kSubmit communicates with the kWorker instances over pipes.
10782 * A job request is written by kSubmit and kWorker read, unpacks it and executes
10783 * it. When the job is completed, kWorker writes a short reply with the exit
10784 * code and an internal status indicating whether it is going to restart.
10785 *
10786 * The kWorker intance will reply to kSubmit before completing all the internal
10787 * cleanup work, so as not to delay the next job execution unnecessarily. This
10788 * includes checking its own memory consumption and checking whether it needs
10789 * restarting. So, a decision to restart unfortunately have to wait till after
10790 * the next job has completed. This is a little bit unfortunate if the next job
10791 * requires a lot of memory and kWorker has already leaked/used a lot.
10792 *
10793 *
10794 * @section sec_kWorker_How_Works How kWorker Works
10795 *
10796 * kWorker will load the executable specified by kSubmit into memory and call
10797 * it's entrypoint in a lightly sandbox'ed environment.
10798 *
10799 *
10800 * @subsection ssec_kWorker_Loaing Image loading
10801 *
10802 * kWorker will manually load all the executable images into memory, fix them
10803 * up, and make a copy of the virgin image so it can be restored using memcpy
10804 * the next time it is used.
10805 *
10806 * Imported functions are monitored and replacements used for a few of them.
10807 * These replacements are serve the following purposes:
10808 * - Provide a different command line.
10809 * - Provide a different environment.
10810 * - Intercept process termination.
10811 * - Intercept thread creation (only linker is allowed to create threads).
10812 * - Intercept file reading for caching (header files, ++) as file system
10813 * access is made even slower by anti-virus software.
10814 * - Intercept crypto hash APIs to cache MD5 digests of header files
10815 * (c1.dll / c1xx.dll spends a noticable bit of time doing MD5).
10816 * - Intercept temporary files (%TEMP%/_CL_XXXXXXyy) to keep the entirely
10817 * in memory as writing files grows expensive with encryption and
10818 * anti-virus software active.
10819 * - Intercept some file system queries to use the kFsCache instead of
10820 * going to the kernel and slowly worm thru the AV filter driver.
10821 * - Intercept standard output/error and console writes to aggressivly
10822 * buffer the output. The MS CRT does not buffer either when it goes to
10823 * the console, resulting in terrible performance and mixing up output
10824 * with other compile jobs.
10825 * This also allows us to filter out the annoying source file announcements
10826 * by cl.exe.
10827 * - Intercept VirtualAlloc and VirtualFree to prevent
10828 * CL.EXE/C1.DLL/C1XX.DLL from leaking some 72MB internal allocat area.
10829 * - Intercept FlsAlloc/FlsFree to make sure the allocations are freed and
10830 * the callbacks run after each job.
10831 * - Intercept HeapCreate/HeapFree to reduce leaks from statically linked
10832 * executables and tools using custom heaps (like the microsoft linker).
10833 * [exectuable images only]
10834 * - Intercept atexit and _onexit registration to be able run them after
10835 * each job instead of crashing as kWorker exits. This also helps avoid
10836 * some leaks. [executable image only]
10837 *
10838 * DLLs falls into two categories, system DLLs which we always load using the
10839 * native loader, and tool DLLs which can be handled like the executable or
10840 * optionally using the native loader. We maintain a hardcoded white listing of
10841 * tool DLLs we trust to load using the native loader.
10842 *
10843 * Imports of natively loaded DLLs are processed too, but we only replace a
10844 * subset of the functions compared to natively loaded excutable and DLL images.
10845 *
10846 * DLLs are never unloaded and we cache LoadLibrary requests (hash the input).
10847 * This is to speed up job execution.
10848 *
10849 * It was thought that we needed to restore (memcpy) natively loaded tool DLLs
10850 * for each job run, but so far this hasn't been necessary.
10851 *
10852 *
10853 * @subsection ssec_kWorker_Optimizing Optimizing the Compiler
10854 *
10855 * The Visual Studio 2010 C/C++ compiler does a poor job at processing header
10856 * files and uses a whole bunch of temporary files (in %TEMP%) for passing
10857 * intermediate representation between the first (c1/c1xx.dll) and second pass
10858 * (c2.dll).
10859 *
10860 * kWorker helps the compiler as best as it can. Given a little knowledge about
10861 * stable and volatile file system areas, it can do a lot of caching that a
10862 * normal compiler driver cannot easily do when given a single file.
10863 *
10864 *
10865 * @subsubsection sssec_kWorker_Headers Cache Headers Files and Searches
10866 *
10867 * The preprocessor part will open and process header files exactly as they are
10868 * encountered in the source files. If string.h is included by the main source
10869 * and five other header files, it will be searched for (include path), opened,
10870 * read, MD5-summed, and pre-processed six times. The last five times is just a
10871 * waste of time because of the guards or \#pragma once. A smart compiler would
10872 * make a little extra effort and realize this.
10873 *
10874 * kWorker will cache help the preprocessor by remembering places where the
10875 * header was not found with help of kFsCache, and cache the file in memory when
10876 * found. The first part is taken care of by intercepting GetFileAttributesW,
10877 * and the latter by intercepting CreateFileW, ReadFile and CloseFile. Once
10878 * cached, the file is kept open and the CreateFileW call returns a duplicate of
10879 * that handle. An internal handle table is used by ReadFile and CloseFile to
10880 * keep track of intercepted handles (also used for temporary file, temporary
10881 * file mappings, console buffering, and standard out/err buffering).
10882 *
10883 * PS. The header search optimization also comes in handy when cl.exe goes on
10884 * thru the whole PATH looking for c1/c1xx.exe and c2.exe after finding
10885 * c1/c1xx.dll and c2.dll. My guess is that the compiler team can
10886 * optionally compile the three pass DLLs as executables during development
10887 * and problem analysis.
10888 *
10889 *
10890 * @subsubsection sssec_kWorker_Temp_Files Temporary Files In Memory
10891 *
10892 * The issues of the temporary files is pretty severe on the Dell machine used
10893 * for benchmarking with full AV and encryption. The synthetic benchmark
10894 * improved by 30% when kWorker implemented measures to keep them entirely in
10895 * memory.
10896 *
10897 * kWorker implement these by recognizing the filename pattern in CreateFileW
10898 * and creating/opening the given file as needed. The handle returned is a
10899 * duplicate of the current process, thus giving us a good chance of catching
10900 * API calls we're not intercepting.
10901 *
10902 * In addition to CreateFileW, we also need to intercept GetFileType, ReadFile,
10903 * WriteFile, SetFilePointer+Ex, SetEndOfFile, and CloseFile. The 2nd pass
10904 * additionally requires GetFileSize+Ex, CreateFileMappingW, MapViewOfFile and
10905 * UnmapViewOfFile.
10906 *
10907 *
10908 * @section sec_kWorker_Numbers Some measurements.
10909 *
10910 * - r2881 building src/VBox/Runtime:
10911 * - without: 2m01.016388s = 120.016388 s
10912 * - with: 1m15.165069s = 75.165069 s => 120.016388s - 75.165069s = 44.851319s => 44.85/120.02 = 37% speed up.
10913 * - r2884 building vbox/debug (r110512):
10914 * - without: 11m14.446609s = 674.446609 s
10915 * - with: 9m01.017344s = 541.017344 s => 674.446609s - 541.017344s = 133.429265 => 133.43/674.45 = 19% speed up
10916 * - r2896 building vbox/debug (r110577):
10917 * - with: 8m31.182384s = 511.182384 s => 674.446609s - 511.182384s = 163.264225 = 163.26/674.45 = 24% speed up
10918 * - r2920 building vbox/debug (r110702) on Skylake (W10/amd64, only standard
10919 * MS Defender as AV):
10920 * - without: 10m24.990389s = 624.990389s
10921 * - with: 08m04.738184s = 484.738184s
10922 * - delta: 624.99s - 484.74s = 140.25s
10923 * - saved: 140.25/624.99 = 22% faster
10924 *
10925 *
10926 * @subsection subsec_kWorker_Early_Numbers Early Experiments
10927 *
10928 * These are some early experiments doing 1024 compilations of
10929 * VBoxBS2Linker.cpp using a hard coded command line and looping in kWorker's
10930 * main function:
10931 *
10932 * Skylake (W10/amd64, only stdandard MS defender):
10933 * - cmd 1: 48 /1024 = 0x0 (0.046875) [for /l %i in (1,1,1024) do ...]
10934 * - kmk 1: 44 /1024 = 0x0 (0.04296875) [all: ; 1024 x cl.exe]
10935 * - run 1: 37 /1024 = 0x0 (0.0361328125) [just process creation gain]
10936 * - run 2: 34 /1024 = 0x0 (0.033203125) [get file attribs]
10937 * - run 3: 32.77 /1024 = 0x0 (0.032001953125) [read caching of headers]
10938 * - run 4: 32.67 /1024 = 0x0 (0.031904296875) [loader tweaking]
10939 * - run 5: 29.144/1024 = 0x0 (0.0284609375) [with temp files in memory]
10940 *
10941 * Dell (W7/amd64, infected by mcafee):
10942 * - kmk 1: 285.278/1024 = 0x0 (0.278591796875)
10943 * - run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
10944 * - run 2: 78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
10945 *
10946 * The command line:
10947 * @code{.cpp}
10948 "\"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/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp"
10949 * @endcode
10950 */
10951
0 # $Id: Makefile.kmk 2907 2016-09-09 22:33:26Z bird $
0 # $Id: Makefile.kmk 2994 2016-11-01 22:41:41Z bird $
11 ## @file
22 # Sub-makefile for kmk / GNU Make.
33 #
8787 kmkbuiltin/setmode.c \
8888 kmkbuiltin/strmode.c \
8989 kmkbuiltin/kbuild_protection.c \
90 kmkbuiltin/common-env-and-cwd-opt.c \
9091 getopt.c \
9192 getopt1.c \
9293 electric.c
278279 kmkbuiltin/mv.c \
279280 kmkbuiltin/ln.c \
280281 kmkbuiltin/printf.c \
282 kmkbuiltin/redirect.c \
281283 kmkbuiltin/rm.c \
282284 kmkbuiltin/rmdir.c \
283285 $(if-expr $(KBUILD_TARGET) == win,kmkbuiltin/kSubmit.c) \
393395 kmkbuiltin/rm.c
394396
395397 kmk_redirect_TEMPLATE = BIN-KMK
396 kmk_redirect_DEFS = kmk_builtin_redirect=main
397398 kmk_redirect_SOURCES = \
398399 kmkbuiltin/redirect.c
399400 kmk_redirect_SOURCES.win = \
529530 tstFileInfo_TEMPLATE = BIN
530531 tstFileInfo_SOURCES = w32/tstFileInfo.c
531532
533 #
534 # tstFileInfo
535 #
536 PROGRAMS.win += tstFtsFake
537 tstFtsFake_TEMPLATE = BIN-KMK
538 tstFtsFake_NOINST = 1
539 tstFtsFake_DEFS = USE_OLD_FTS
540 tstFtsFake_SOURCES = ../lib/nt/tstNtFts.c
541
542
532543
533544 include $(FILE_KBUILD_SUB_FOOTER)
534545
544555 #
545556 # Some missing headers.
546557 #
558 if1of ($(KBUILD_TARGET), win nt)
559 $(kmk_0_OUTDIR)/fts.h: $(MAKEFILE) | $(call DIRDEP,$(kmk_0_OUTDIR))
560 $(APPEND) -t "$@" "#include <nt/fts-nt.h>"
561 else
547562 $(kmk_0_OUTDIR)/fts.h: $(kmk_DEFPATH)/kmkbuiltin/ftsfake.h | $(call DIRDEP,$(kmk_0_OUTDIR))
548563 $(CP) $^ $@
564 endif
549565
550566 $(kmk_0_OUTDIR)/unistd.h: | $(call DIRDEP,$(kmk_0_OUTDIR))
551567 $(ECHO_EXT) > $@
0 /* $Id: dir-nt-bird.c 2886 2016-09-06 14:31:46Z bird $ */
0 /* $Id: dir-nt-bird.c 2948 2016-09-20 15:36:07Z bird $ */
11 /** @file
22 * Reimplementation of dir.c for NT using kFsCache.
33 *
119119 fRc = 1;
120120 else
121121 {
122 PKFSOBJ pNameObj = kFsCacheLookupRelativeToDirA(g_pFsCache, (PKFSDIR)pDirObj,
123 pszName, strlen(pszName), &enmError, NULL);
122 PKFSOBJ pNameObj = kFsCacheLookupRelativeToDirA(g_pFsCache, (PKFSDIR)pDirObj, pszName, strlen(pszName),
123 0/*fFlags*/, &enmError, NULL);
124124 if (pNameObj)
125125 {
126126 fRc = pNameObj->bObjType == KFSOBJ_TYPE_MISSING;
411411 }
412412
413413
414 /**
415 * Print statitstics.
416 */
417 void print_dir_stats(void)
418 {
419 FILE *pOut = stdout;
420 KU32 cMisses;
421
422 fputs("\n"
423 "# NT dir cache stats:\n", pOut);
424 fprintf(pOut, "# %u objects, taking up %u (%#x) bytes, avg %u bytes\n",
425 g_pFsCache->cObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects / g_pFsCache->cObjects);
426 fprintf(pOut, "# %u A path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collision\n",
427 g_pFsCache->cAnsiPaths, g_pFsCache->cbAnsiPaths, g_pFsCache->cbAnsiPaths,
428 g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1), g_pFsCache->cAnsiPathCollisions);
429 #ifdef KFSCACHE_CFG_UTF16
430 fprintf(pOut, "# %u W path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collisions\n",
431 g_pFsCache->cUtf16Paths, g_pFsCache->cbUtf16Paths, g_pFsCache->cbUtf16Paths,
432 g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1), g_pFsCache->cUtf16PathCollisions);
433 #endif
434 fprintf(pOut, "# %u child hash tables, total of %u entries, %u children inserted, %u collisions\n",
435 g_pFsCache->cChildHashTabs, g_pFsCache->cChildHashEntriesTotal,
436 g_pFsCache->cChildHashed, g_pFsCache->cChildHashCollisions);
437
438 cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits;
439 fprintf(pOut, "# %u lookups: %u (%" KU64_PRI " %%) path hash hits, %u (%" KU64_PRI "%%) walks hits, %u (%" KU64_PRI "%%) misses\n",
440 g_pFsCache->cLookups,
441 g_pFsCache->cPathHashHits, g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1),
442 g_pFsCache->cWalkHits, g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1),
443 cMisses, cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1));
444 fprintf(pOut, "# %u child searches, %u (%" KU64_PRI "%%) hash hits\n",
445 g_pFsCache->cChildSearches,
446 g_pFsCache->cChildHashHits, g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1));
447 }
448
449
414450 void print_dir_data_base(void)
415451 {
416452 /** @todo. */
417 }
418
419
420
453
454 }
455
456
457 /* duplicated in kWorker.c */
421458 void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
422459 {
423460 KFSLOOKUPERROR enmError;
439476 {
440477 kHlpAssert(off > 1);
441478 kHlpAssert(pAncestor != NULL);
442 kHlpAssert(pAncestor->ObjcchName > 0);
479 kHlpAssert(pAncestor->Obj.cchName > 0);
443480 pszFull[--off] = '/';
444481 off -= pAncestor->Obj.cchName;
445482 kHlpAssert(pAncestor->Obj.cchParent == off);
584621 return -1;
585622 }
586623
624 /**
625 * Invalidates a deleted directory so the cache can close handles to it.
626 *
627 * Used by kmk_builtin_rm and kmk_builtin_rmdir.
628 *
629 * @returns 0 on success, -1 on failure.
630 * @param pszDir The directory to invalidate as deleted.
631 */
632 int dir_cache_deleted_directory(const char *pszDir)
633 {
634 if (kFsCacheInvalidateDeletedDirectoryA(g_pFsCache, pszDir))
635 return 0;
636 return -1;
637 }
638
639
640 int kmk_builtin_dircache(int argc, char **argv, char **envp)
641 {
642 if (argc >= 2)
643 {
644 const char *pszCmd = argv[1];
645 if (strcmp(pszCmd, "invalidate") == 0)
646 {
647 if (argc == 2)
648 {
649 dir_cache_invalid_all();
650 return 0;
651 }
652 fprintf(stderr, "kmk_builtin_dircache: the 'invalidate' command takes no arguments!\n");
653 }
654 else if (strcmp(pszCmd, "invalidate-missing") == 0)
655 {
656 if (argc == 2)
657 {
658 dir_cache_invalid_missing ();
659 return 0;
660 }
661 fprintf(stderr, "kmk_builtin_dircache: the 'invalidate-missing' command takes no arguments!\n");
662 }
663 else if (strcmp(pszCmd, "volatile") == 0)
664 {
665 int i;
666 for (i = 2; i < argc; i++)
667 dir_cache_volatile_dir(argv[i]);
668 return 0;
669 }
670 else if (strcmp(pszCmd, "deleted") == 0)
671 {
672 int i;
673 for (i = 2; i < argc; i++)
674 dir_cache_deleted_directory(argv[i]);
675 return 0;
676 }
677 else
678 fprintf(stderr, "kmk_builtin_dircache: Invalid command '%s'!\n", pszCmd);
679 }
680 else
681 fprintf(stderr, "kmk_builtin_dircache: No command given!\n");
682
683 K_NOREF(envp);
684 return 2;
685 }
686
13281328 #endif
13291329 }
13301330
1331 #ifdef CONFIG_WITH_PRINT_STATS_SWITCH
1332 /* Print stats */
1333
1334 void print_dir_stats (void)
1335 {
1336 /** @todo normal dir stats. */
1337 }
1338 #endif
1339
13311340 /* Hooks for globbing. */
13321341
13331342 #if defined(KMK) && !defined(__OS2__)
54725472 dir_cache_volatile_dir (dir);
54735473 }
54745474 }
5475 else if (strcmp (cmd, "deleted") == 0)
5476 {
5477 size_t i;
5478 for (i = 1; argv[i] != NULL; i++)
5479 {
5480 const char *dir = argv[i];
5481 while (isblank ((unsigned char)*dir))
5482 dir++;
5483 if (*dir)
5484 dir_cache_deleted_directory (dir);
5485 }
5486 }
54755487 else
54765488 error (reading_file, "Unknown $(dircache-ctl ) command: '%s'", cmd);
54775489 # endif
0 /* $Id: common-env-and-cwd-opt.c 2912 2016-09-14 13:36:15Z bird $ */
1 /** @file
2 * kMk Builtin command - Commmon environment and CWD option handling code.
3 */
4
5 /*
6 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
7 *
8 * This file is part of kBuild.
9 *
10 * kBuild is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * kBuild is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
22 *
23 */
24
25 /*******************************************************************************
26 * Header Files *
27 *******************************************************************************/
28 #include "config.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "kmkbuiltin.h"
34 #include "err.h"
35
36
37 /** The environment variable compare function.
38 * We must use case insensitive compare on windows (Path vs PATH). */
39 #ifdef KBUILD_OS_WINDOWS
40 # define KSUBMIT_ENV_NCMP _strnicmp
41 #else
42 # define KSUBMIT_ENV_NCMP strncmp
43 #endif
44
45
46 /**
47 * Handles the --set var=value option.
48 *
49 * @returns 0 on success, non-zero exit code on error.
50 * @param papszEnv The environment vector.
51 * @param pcEnvVars Pointer to the variable holding the number of
52 * environment variables held by @a papszEnv.
53 * @param pcAllocatedEnvVars Pointer to the variable holding max size of the
54 * environment vector.
55 * @param cVerbosity The verbosity level.
56 * @param pszValue The var=value string to apply.
57 */
58 int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue)
59 {
60 const char *pszEqual = strchr(pszValue, '=');
61 if (pszEqual)
62 {
63 char **papszEnv = *ppapszEnv;
64 unsigned iEnvVar;
65 unsigned cEnvVars = *pcEnvVars;
66 size_t const cchVar = pszEqual - pszValue;
67 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
68 {
69 char *pszCur = papszEnv[iEnvVar];
70 if ( KSUBMIT_ENV_NCMP(pszCur, pszValue, cchVar) == 0
71 && pszCur[cchVar] == '=')
72 {
73 if (cVerbosity > 0)
74 warnx("replacing '%s' with '%s'", papszEnv[iEnvVar], pszValue);
75 free(papszEnv[iEnvVar]);
76 papszEnv[iEnvVar] = strdup(pszValue);
77 if (!papszEnv[iEnvVar])
78 return errx(1, "out of memory!");
79 break;
80 }
81 }
82 if (iEnvVar == cEnvVars)
83 {
84 /* Append new variable. We probably need to resize the vector. */
85 if ((cEnvVars + 2) > *pcAllocatedEnvVars)
86 {
87 *pcAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
88 papszEnv = (char **)realloc(papszEnv, *pcAllocatedEnvVars * sizeof(papszEnv[0]));
89 if (!papszEnv)
90 return errx(1, "out of memory!");
91 *ppapszEnv = papszEnv;
92 }
93 papszEnv[cEnvVars] = strdup(pszValue);
94 if (!papszEnv[cEnvVars])
95 return errx(1, "out of memory!");
96 papszEnv[++cEnvVars] = NULL;
97 *pcEnvVars = cEnvVars;
98 if (cVerbosity > 0)
99 warnx("added '%s'", papszEnv[iEnvVar]);
100 }
101 else
102 {
103 /* Check for duplicates. */
104 for (iEnvVar++; iEnvVar < cEnvVars; iEnvVar++)
105 if ( KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszValue, cchVar) == 0
106 && papszEnv[iEnvVar][cchVar] == '=')
107 {
108 if (cVerbosity > 0)
109 warnx("removing duplicate '%s'", papszEnv[iEnvVar]);
110 free(papszEnv[iEnvVar]);
111 cEnvVars--;
112 if (iEnvVar != cEnvVars)
113 papszEnv[iEnvVar] = papszEnv[cEnvVars];
114 papszEnv[cEnvVars] = NULL;
115 iEnvVar--;
116 }
117 }
118 }
119 else
120 return errx(1, "Missing '=': -E %s", pszValue);
121
122 return 0;
123 }
124
125
126 /**
127 * Handles the --unset var option.
128 *
129 * @returns 0 on success, non-zero exit code on error.
130 * @param papszEnv The environment vector.
131 * @param pcEnvVars Pointer to the variable holding the number of
132 * environment variables held by @a papszEnv.
133 * @param cVerbosity The verbosity level.
134 * @param pszVarToRemove The name of the variable to remove.
135 */
136 int kBuiltinOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove)
137 {
138 if (strchr(pszVarToRemove, '=') == NULL)
139 {
140 unsigned cRemoved = 0;
141 size_t const cchVar = strlen(pszVarToRemove);
142 unsigned cEnvVars = *pcEnvVars;
143 unsigned iEnvVar;
144
145 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
146 if ( KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszVarToRemove, cchVar) == 0
147 && papszEnv[iEnvVar][cchVar] == '=')
148 {
149 if (cVerbosity > 0)
150 warnx(!cRemoved ? "removing '%s'" : "removing duplicate '%s'", papszEnv[iEnvVar]);
151 free(papszEnv[iEnvVar]);
152 cEnvVars--;
153 if (iEnvVar != cEnvVars)
154 papszEnv[iEnvVar] = papszEnv[cEnvVars];
155 papszEnv[cEnvVars] = NULL;
156 cRemoved++;
157 iEnvVar--;
158 }
159 *pcEnvVars = cEnvVars;
160
161 if (cVerbosity > 0 && !cRemoved)
162 warnx("not found '%s'", pszVarToRemove);
163 }
164 else
165 return errx(1, "Found invalid variable name character '=' in: -U %s", pszVarToRemove);
166 return 0;
167 }
168
169
170
171 /**
172 * Handles the --chdir dir option.
173 *
174 * @returns 0 on success, non-zero exit code on error.
175 * @param pszCwd The CWD buffer. Contains current CWD on input,
176 * modified by @a pszValue on output.
177 * @param cbCwdBuf The size of the CWD buffer.
178 * @param pszValue The --chdir value to apply.
179 */
180 int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue)
181 {
182 size_t cchNewCwd = strlen(pszValue);
183 size_t offDst;
184 if (cchNewCwd)
185 {
186 #ifdef HAVE_DOS_PATHS
187 if (*pszValue == '/' || *pszValue == '\\')
188 {
189 if (pszValue[1] == '/' || pszValue[1] == '\\')
190 offDst = 0; /* UNC */
191 else if (pszCwd[1] == ':' && isalpha(pszCwd[0]))
192 offDst = 2; /* Take drive letter from CWD. */
193 else
194 return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", pszCwd, pszValue);
195 }
196 else if ( pszValue[1] == ':'
197 && isalpha(pszValue[0]))
198 {
199 if (pszValue[2] == '/'|| pszValue[2] == '\\')
200 offDst = 0; /* DOS style absolute path. */
201 else if ( pszCwd[1] == ':'
202 && tolower(pszCwd[0]) == tolower(pszValue[0]) )
203 {
204 pszValue += 2; /* Same drive as CWD, append drive relative path from value. */
205 cchNewCwd -= 2;
206 offDst = strlen(pszCwd);
207 }
208 else
209 {
210 /* Get current CWD on the specified drive and append value. */
211 int iDrive = tolower(pszValue[0]) - 'a' + 1;
212 if (!_getdcwd(iDrive, pszCwd, cbCwdBuf))
213 return err(1, "_getdcwd(%d,,) failed", iDrive);
214 pszValue += 2;
215 cchNewCwd -= 2;
216 }
217 }
218 #else
219 if (*pszValue == '/')
220 offDst = 0;
221 #endif
222 else
223 offDst = strlen(pszCwd); /* Relative path, append to the existing CWD value. */
224
225 /* Do the copying. */
226 #ifdef HAVE_DOS_PATHS
227 if (offDst > 0 && pszCwd[offDst - 1] != '/' && pszCwd[offDst - 1] != '\\')
228 #else
229 if (offDst > 0 && pszCwd[offDst - 1] != '/')
230 #endif
231 pszCwd[offDst++] = '/';
232 if (offDst + cchNewCwd >= cbCwdBuf)
233 return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, pszCwd, pszValue);
234 memcpy(&pszCwd[offDst], pszValue, cchNewCwd + 1);
235 }
236 /* else: relative, no change - quitely ignore. */
237 return 0;
238 }
239
220220 case 'p':
221221 pflag = 1;
222222 break;
223 #if 0 /* only one -R */
224223 case 'r':
225224 rflag = 1;
226225 break;
227 #endif
228226 case 'v':
229227 vflag = 1;
230228 break;
694692 " -f Force. Overrides -i and -n.\n"
695693 " -i Iteractive. Overrides -n and -f.\n"
696694 " -n Don't overwrite any files. Overrides -i and -f.\n"
695 " -v Verbose.\n"
697696 " --ignore-non-existing\n"
698697 " Don't fail if the specified source file doesn't exist.\n"
699698 " --changed\n"
0 /* $Id: kDepIDB.c 2856 2016-09-01 02:42:08Z bird $ */
0 /* $Id: kDepIDB.c 2955 2016-09-21 19:05:53Z bird $ */
11 /** @file
22 * kDepIDB - Extract dependency information from a MS Visual C++ .idb file.
33 */
863863 */
864864 if (!i)
865865 {
866 depOptimize(fFixCase, fQuiet);
866 depOptimize(fFixCase, fQuiet, NULL /*pszIgnoredExt*/);
867867 fprintf(pOutput, "%s:", pszTarget);
868868 depPrint(pOutput);
869869 if (fStubs)
0 /* $Id: kDepObj.c 2896 2016-09-08 15:32:09Z bird $ */
0 /* $Id: kDepObj.c 2955 2016-09-21 19:05:53Z bird $ */
11 /** @file
22 * kDepObj - Extract dependency information from an object file.
33 */
972972
973973 static void usage(const char *a_argv0)
974974 {
975 printf("usage: %s -o <output> -t <target> [-fqs] <OMF-file>\n"
975 printf("usage: %s -o <output> -t <target> [-fqs] [-e <ignore-ext>] <OMF or COFF file>\n"
976976 " or: %s --help\n"
977977 " or: %s --version\n",
978978 a_argv0, a_argv0, a_argv0);
990990 const char *pszTarget = NULL;
991991 int fStubs = 0;
992992 int fFixCase = 0;
993 const char *pszIgnoreExt = NULL;
993994 /* Argument parsing. */
994995 int fInput = 0; /* set when we've found input argument. */
995996 int fQuiet = 0;
10081009 {
10091010 if (argv[i][0] == '-')
10101011 {
1012 const char *pszValue;
10111013 const char *psz = &argv[i][1];
1012 if (*psz == '-')
1014 char chOpt;
1015 chOpt = *psz++;
1016 if (chOpt == '-')
10131017 {
1014 if (!strcmp(psz, "-quiet"))
1015 psz = "q";
1016 else if (!strcmp(psz, "-help"))
1017 psz = "?";
1018 else if (!strcmp(psz, "-version"))
1019 psz = "V";
1018 /* Convert long to short option. */
1019 if (!strcmp(psz, "quiet"))
1020 chOpt = 'q';
1021 else if (!strcmp(psz, "help"))
1022 chOpt = '?';
1023 else if (!strcmp(psz, "version"))
1024 chOpt = 'V';
1025 else
1026 {
1027 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
1028 usage(argv[0]);
1029 return 2;
1030 }
1031 psz = "";
10201032 }
10211033
1022 switch (*psz)
1034 /*
1035 * Requires value?
1036 */
1037 switch (chOpt)
1038 {
1039 case 'o':
1040 case 't':
1041 case 'e':
1042 if (*psz)
1043 pszValue = psz;
1044 else if (++i < argc)
1045 pszValue = argv[i];
1046 else
1047 {
1048 fprintf(stderr, "%s: syntax error: The '-%c' option takes a value.\n", chOpt);
1049 return 2;
1050 }
1051 break;
1052
1053 default:
1054 pszValue = NULL;
1055 break;
1056 }
1057
1058
1059 switch (chOpt)
10231060 {
10241061 /*
10251062 * Output file.
10261063 */
10271064 case 'o':
10281065 {
1029 pszOutput = &argv[i][2];
10301066 if (pOutput)
10311067 {
10321068 fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
1033 return 1;
1069 return 2;
10341070 }
1035 if (!*pszOutput)
1036 {
1037 if (++i >= argc)
1038 {
1039 fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
1040 return 1;
1041 }
1042 pszOutput = argv[i];
1043 }
1071 pszOutput = pszValue;
10441072 if (pszOutput[0] == '-' && !pszOutput[1])
10451073 pOutput = stdout;
10461074 else
10631091 fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
10641092 return 1;
10651093 }
1066 pszTarget = &argv[i][2];
1067 if (!*pszTarget)
1068 {
1069 if (++i >= argc)
1070 {
1071 fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
1072 return 1;
1073 }
1074 pszTarget = argv[i];
1075 }
1094 pszTarget = pszValue;
10761095 break;
10771096 }
10781097
11001119 case 's':
11011120 {
11021121 fStubs = 1;
1122 break;
1123 }
1124
1125 /*
1126 * Extension to ignore.
1127 */
1128 case 'e':
1129 {
1130 if (pszIgnoreExt)
1131 {
1132 fprintf(stderr, "%s: syntax error: The '-e' option can only be used once!\n");
1133 return 2;
1134 }
1135 pszIgnoreExt = pszValue;
11031136 break;
11041137 }
11051138
11191152 default:
11201153 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
11211154 usage(argv[0]);
1122 return 1;
1155 return 2;
11231156 }
11241157 }
11251158 else
11771210 */
11781211 if (!i)
11791212 {
1180 depOptimize(fFixCase, fQuiet);
1213 depOptimize(fFixCase, fQuiet, pszIgnoreExt);
11811214 fprintf(pOutput, "%s:", pszTarget);
11821215 depPrint(pOutput);
11831216 if (fStubs)
0 /* $Id: kSubmit.c 2894 2016-09-08 13:27:56Z bird $ */
0 /* $Id: kSubmit.c 2959 2016-09-21 20:53:32Z bird $ */
11 /** @file
22 * kMk Builtin command - submit job to a kWorker.
33 */
572572 * @param papszEnvVars The environment vector.
573573 * @param pszCwd The current directory.
574574 * @param fWatcomBrainDamage The wcc/wcc386 workaround.
575 * @param fNoPchCaching Whether to disable precompiled header caching.
575576 * @param papszPostCmdArgs The post command and it's arguments.
576577 * @param cPostCmdArgs Number of post command argument, including the
577578 * command. Zero if no post command scheduled.
578579 * @param pcbMsg Where to return the message length.
579580 */
580581 static void *kSubmitComposeJobMessage(const char *pszExecutable, char **papszArgs, char **papszEnvVars,
581 const char *pszCwd, int fWatcomBrainDamage,
582 const char *pszCwd, int fWatcomBrainDamage, int fNoPchCaching,
582583 char **papszPostCmdArgs, uint32_t cPostCmdArgs, uint32_t *pcbMsg)
583584 {
584585 size_t cbTmp;
613614 cbMsg += strlen(papszEnvVars[i]) + 1;
614615 cEnvVars = i;
615616
616 cbMsg += 1;
617 cbMsg += 1; /* fWatcomBrainDamage */
618 cbMsg += 1; /* fNoPchCaching */
617619
618620 cbMsg += sizeof(cPostCmdArgs);
619621 for (i = 0; i < cPostCmdArgs; i++)
665667
666668 /* flags */
667669 *pbCursor++ = fWatcomBrainDamage != 0;
670 *pbCursor++ = fNoPchCaching != 0;
668671
669672 /* post command */
670673 memcpy(pbCursor, &cPostCmdArgs, sizeof(cPostCmdArgs));
10941097 DWORD cMsElapsed = GetTickCount() - msStartTick;
10951098 DWORD dwWait = WaitForMultipleObjects(cHandles <= MAXIMUM_WAIT_OBJECTS ? cHandles : MAXIMUM_WAIT_OBJECTS,
10961099 ahHandles, FALSE /*bWaitAll*/,
1097 cMsElapsed < 1000 ? 1000 - cMsElapsed + 16 : 16);
1100 cMsElapsed < 5000 ? 5000 - cMsElapsed + 16 : 16);
10981101 if ( dwWait >= WAIT_OBJECT_0
10991102 && dwWait <= WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)
11001103 {
11211124 {
11221125 /* Terminate the whole bunch. */
11231126 cKillRaids++;
1124 if (cKillRaids <= 2)
1127 if (cKillRaids == 1 && getenv("KMK_KSUBMIT_NO_KILL") == NULL)
11251128 {
11261129 fprintf(stderr, "kmk/kSubmit: Killing %u lingering worker processe(s)!\n", cHandles);
11271130 for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
11341137 else
11351138 {
11361139 fprintf(stderr, "kmk/kSubmit: Giving up on the last %u worker processe(s). :-(\n", cHandles);
1137 break;
1140 return;
11381141 }
11391142 }
11401143 else
11601163 }
11611164
11621165
1163 /** The environment variable compare function.
1164 * We must use case insensitive compare on windows (Path vs PATH). */
1165 #ifdef KBUILD_OS_WINDOWS
1166 # define KSUBMIT_ENV_NCMP _strnicmp
1167 #else
1168 # define KSUBMIT_ENV_NCMP strncmp
1169 #endif
1170
1171
1172 /**
1173 * Handles the --set var=value option.
1174 *
1175 * @returns 0 on success, non-zero exit code on error.
1176 * @param papszEnv The environment vector.
1177 * @param pcEnvVars Pointer to the variable holding the number of
1178 * environment variables held by @a papszEnv.
1179 * @param pcAllocatedEnvVars Pointer to the variable holding max size of the
1180 * environment vector.
1181 * @param cVerbosity The verbosity level.
1182 * @param pszValue The var=value string to apply.
1183 */
1184 static int kSubmitOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
1185 int cVerbosity, const char *pszValue)
1186 {
1187 const char *pszEqual = strchr(pszValue, '=');
1188 if (pszEqual)
1189 {
1190 char **papszEnv = *ppapszEnv;
1191 unsigned iEnvVar;
1192 unsigned cEnvVars = *pcEnvVars;
1193 size_t const cchVar = pszEqual - pszValue;
1194 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
1195 {
1196 char *pszCur = papszEnv[iEnvVar];
1197 if ( KSUBMIT_ENV_NCMP(pszCur, pszValue, cchVar) == 0
1198 && pszCur[cchVar] == '=')
1199 {
1200 if (cVerbosity > 0)
1201 fprintf(stderr, "kSubmit: replacing '%s' with '%s'\n", papszEnv[iEnvVar], pszValue);
1202 free(papszEnv[iEnvVar]);
1203 papszEnv[iEnvVar] = xstrdup(pszValue);
1204 break;
1205 }
1206 }
1207 if (iEnvVar == cEnvVars)
1208 {
1209 /* Append new variable. We probably need to resize the vector. */
1210 if ((cEnvVars + 2) > *pcAllocatedEnvVars)
1211 {
1212 *pcAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
1213 *ppapszEnv = papszEnv = (char **)xrealloc(papszEnv, *pcAllocatedEnvVars * sizeof(papszEnv[0]));
1214 }
1215 papszEnv[cEnvVars++] = xstrdup(pszValue);
1216 papszEnv[cEnvVars] = NULL;
1217 *pcEnvVars = cEnvVars;
1218 if (cVerbosity > 0)
1219 fprintf(stderr, "kSubmit: added '%s'\n", papszEnv[iEnvVar]);
1220 }
1221 else
1222 {
1223 /* Check for duplicates. */
1224 for (iEnvVar++; iEnvVar < cEnvVars; iEnvVar++)
1225 if ( KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszValue, cchVar) == 0
1226 && papszEnv[iEnvVar][cchVar] == '=')
1227 {
1228 if (cVerbosity > 0)
1229 fprintf(stderr, "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
1230 free(papszEnv[iEnvVar]);
1231 cEnvVars--;
1232 if (iEnvVar != cEnvVars)
1233 papszEnv[iEnvVar] = papszEnv[cEnvVars];
1234 papszEnv[cEnvVars] = NULL;
1235 iEnvVar--;
1236 }
1237 }
1238 }
1239 else
1240 return errx(1, "Missing '=': -E %s", pszValue);
1241
1242 return 0;
1243 }
1244
1245
1246 /**
1247 * Handles the --unset var option.
1248 *
1249 * @returns 0 on success, non-zero exit code on error.
1250 * @param papszEnv The environment vector.
1251 * @param pcEnvVars Pointer to the variable holding the number of
1252 * environment variables held by @a papszEnv.
1253 * @param cVerbosity The verbosity level.
1254 * @param pszVarToRemove The name of the variable to remove.
1255 */
1256 static int kSubmitOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove)
1257 {
1258 if (strchr(pszVarToRemove, '=') == NULL)
1259 {
1260 unsigned cRemoved = 0;
1261 size_t const cchVar = strlen(pszVarToRemove);
1262 unsigned cEnvVars = *pcEnvVars;
1263 unsigned iEnvVar;
1264
1265 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
1266 if ( KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszVarToRemove, cchVar) == 0
1267 && papszEnv[iEnvVar][cchVar] == '=')
1268 {
1269 if (cVerbosity > 0)
1270 fprintf(stderr, !cRemoved ? "kSubmit: removing '%s'\n"
1271 : "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
1272 free(papszEnv[iEnvVar]);
1273 cEnvVars--;
1274 if (iEnvVar != cEnvVars)
1275 papszEnv[iEnvVar] = papszEnv[cEnvVars];
1276 papszEnv[cEnvVars] = NULL;
1277 cRemoved++;
1278 iEnvVar--;
1279 }
1280 *pcEnvVars = cEnvVars;
1281
1282 if (cVerbosity > 0 && !cRemoved)
1283 fprintf(stderr, "kSubmit: not found '%s'\n", pszVarToRemove);
1284 }
1285 else
1286 return errx(1, "Found invalid variable name character '=' in: -U %s", pszVarToRemove);
1287 return 0;
1288 }
1289
1290
1291
1292 /**
1293 * Handles the --chdir dir option.
1294 *
1295 * @returns 0 on success, non-zero exit code on error.
1296 * @param pszCwd The CWD buffer. Contains current CWD on input,
1297 * modified by @a pszValue on output.
1298 * @param cbCwdBuf The size of the CWD buffer.
1299 * @param pszValue The --chdir value to apply.
1300 */
1301 static int kSubmitOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue)
1302 {
1303 size_t cchNewCwd = strlen(pszValue);
1304 size_t offDst;
1305 if (cchNewCwd)
1306 {
1307 #ifdef HAVE_DOS_PATHS
1308 if (*pszValue == '/' || *pszValue == '\\')
1309 {
1310 if (pszValue[1] == '/' || pszValue[1] == '\\')
1311 offDst = 0; /* UNC */
1312 else if (pszCwd[1] == ':' && isalpha(pszCwd[0]))
1313 offDst = 2; /* Take drive letter from CWD. */
1314 else
1315 return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", pszCwd, pszValue);
1316 }
1317 else if ( pszValue[1] == ':'
1318 && isalpha(pszValue[0]))
1319 {
1320 if (pszValue[2] == '/'|| pszValue[2] == '\\')
1321 offDst = 0; /* DOS style absolute path. */
1322 else if ( pszCwd[1] == ':'
1323 && tolower(pszCwd[0]) == tolower(pszValue[0]) )
1324 {
1325 pszValue += 2; /* Same drive as CWD, append drive relative path from value. */
1326 cchNewCwd -= 2;
1327 offDst = strlen(pszCwd);
1328 }
1329 else
1330 {
1331 /* Get current CWD on the specified drive and append value. */
1332 int iDrive = tolower(pszValue[0]) - 'a' + 1;
1333 if (!_getdcwd(iDrive, pszCwd, cbCwdBuf))
1334 return err(1, "_getdcwd(%d,,) failed", iDrive);
1335 pszValue += 2;
1336 cchNewCwd -= 2;
1337 }
1338 }
1339 #else
1340 if (*pszValue == '/')
1341 offDst = 0;
1342 #endif
1343 else
1344 offDst = strlen(pszCwd); /* Relative path, append to the existing CWD value. */
1345
1346 /* Do the copying. */
1347 #ifdef HAVE_DOS_PATHS
1348 if (offDst > 0 && pszCwd[offDst - 1] != '/' && pszCwd[offDst - 1] != '\\')
1349 #else
1350 if (offDst > 0 && pszCwd[offDst - 1] != '/')
1351 #endif
1352 pszCwd[offDst++] = '/';
1353 if (offDst + cchNewCwd >= cbCwdBuf)
1354 return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, pszCwd, pszValue);
1355 memcpy(&pszCwd[offDst], pszValue, cchNewCwd + 1);
1356 }
1357 /* else: relative, no change - quitely ignore. */
1358 return 0;
1359 }
1360
1361
13621166 static int usage(FILE *pOut, const char *argv0)
13631167 {
13641168 fprintf(pOut,
13651169 "usage: %s [-Z|--zap-env] [-E|--set <var=val>] [-U|--unset <var=val>]\n"
1366 " [-C|--chdir <dir>] [--wcc-brain-damage]\n"
1170 " [-C|--chdir <dir>] [--wcc-brain-damage] [--no-pch-caching]\n"
13671171 " [-3|--32-bit] [-6|--64-bit] [-v]\n"
13681172 " [-P|--post-cmd <cmd> [args]] -- <program> [args]\n"
13691173 " or: %s --help\n"
13861190 " --wcc-brain-damage\n"
13871191 " Works around wcc and wcc386 (Open Watcom) not following normal\n"
13881192 " quoting conventions on Windows, OS/2, and DOS.\n"
1193 " --no-pch-caching\n"
1194 " Do not cache precompiled header files because they're being created.\n"
13891195 " -v,--verbose\n"
13901196 " More verbose execution.\n"
13911197 " -P|--post-cmd <cmd> ...\n"
13991205 "\n"
14001206 ,
14011207 argv0, argv0, argv0);
1402 return 1;
1208 return 2;
14031209 }
14041210
14051211
14121218 unsigned cEnvVars;
14131219 char **papszEnv = NULL;
14141220 const char *pszExecutable = NULL;
1415 const char *pszCwd = NULL;
14161221 int iPostCmd = argc;
14171222 int cPostCmdArgs = 0;
14181223 unsigned cBitsWorker = g_cArchBits;
14191224 int fWatcomBrainDamage = 0;
1225 int fNoPchCaching = 0;
14201226 int cVerbosity = 0;
14211227 size_t const cbCwdBuf = GET_PATH_MAX;
14221228 PATH_VAR(szCwd);
14721278 || strcmp(pszArg, "watcom-brain-damage") == 0)
14731279 {
14741280 fWatcomBrainDamage = 1;
1281 continue;
1282 }
1283
1284 if (strcmp(pszArg, "no-pch-caching") == 0)
1285 {
1286 fNoPchCaching = 1;
14751287 continue;
14761288 }
14771289
15011313 chOpt = 'e';
15021314 else
15031315 {
1504 errx(1, "Unknown option: '%s'", pszArg - 2);
1316 errx(2, "Unknown option: '%s'", pszArg - 2);
15051317 return usage(stderr, argv[0]);
15061318 }
15071319 pszArg = "";
15401352 break;
15411353
15421354 case 'E':
1543 rcExit = kSubmitOptEnvSet(&papszEnv, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
1355 rcExit = kBuiltinOptEnvSet(&papszEnv, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
15441356 pChild->environment = papszEnv;
15451357 if (rcExit == 0)
15461358 break;
15471359 return rcExit;
15481360
15491361 case 'U':
1550 rcExit = kSubmitOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszValue);
1362 rcExit = kBuiltinOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszValue);
15511363 if (rcExit == 0)
15521364 break;
15531365 return rcExit;
15541366
15551367 case 'C':
1556 rcExit = kSubmitOptChDir(szCwd, cbCwdBuf, pszValue);
1368 rcExit = kBuiltinOptChDir(szCwd, cbCwdBuf, pszValue);
15571369 if (rcExit == 0)
15581370 break;
15591371 return rcExit;
16111423 {
16121424 uint32_t cbMsg;
16131425 void *pvMsg = kSubmitComposeJobMessage(pszExecutable, &argv[iArg], papszEnv, szCwd,
1614 fWatcomBrainDamage, &argv[iPostCmd], cPostCmdArgs, &cbMsg);
1426 fWatcomBrainDamage, fNoPchCaching,
1427 &argv[iPostCmd], cPostCmdArgs, &cbMsg);
16151428 PWORKERINSTANCE pWorker = kSubmitSelectWorkSpawnNewIfNecessary(cBitsWorker, cVerbosity);
16161429 if (pWorker)
16171430 {
0 /* $Id: md5sum.c 2414 2010-09-12 18:42:06Z bird $ */
0 /* $Id: md5sum.c 2984 2016-11-01 18:24:11Z bird $ */
11 /** @file
22 * md5sum.
33 */
298298 {
299299 int cb;
300300 int rc = 0;
301 char abBuf[32*1024];
302301 struct MD5Context Ctx;
303302 unsigned uPercent = 0;
304 double cbFile = 0.0;
305303 double off = 0.0;
306
307 if (fProgress)
308 {
309 cbFile = size_file(pvFile);
310 if (cbFile < 1024*1024)
311 fProgress = 0;
312 }
304 double cbFile = size_file(pvFile);
305
306 /* Get a decent sized buffer assuming we'll be spending more time reading
307 from the storage than doing MD5 sums. (2MB was choosen based on recent
308 SATA storage benchmarks which used that block size for sequential
309 tests.) We align the buffer address on a 16K boundrary to avoid most
310 transfer alignment issues. */
311 char *pabBufAligned;
312 size_t const cbBufAlign = 16*1024 - 1;
313 size_t const cbBufMax = 2048*1024;
314 size_t cbBuf = cbFile >= cbBufMax ? cbBufMax : ((size_t)cbFile + cbBufAlign) & ~(size_t)cbBufAlign;
315 char *pabBuf = (char *)malloc(cbBuf + cbBufAlign);
316 if (pabBuf)
317 pabBufAligned = (char *)(((uintptr_t)pabBuf + cbBufAlign) & ~(uintptr_t)cbBufAlign );
318 else
319 {
320 do
321 {
322 cbBuf /= 2;
323 pabBuf = (char *)malloc(cbBuf);
324 } while (!pabBuf && cbBuf > 4096);
325 if (!pabBuf)
326 return ENOMEM;
327 pabBufAligned = pabBuf;
328 }
329
330 if (cbFile < cbBuf * 4)
331 fProgress = 0;
313332
314333 MD5Init(&Ctx);
315334 for (;;)
316335 {
317336 /* process a chunk. */
318 cb = read_file(pvFile, abBuf, sizeof(abBuf));
337 cb = read_file(pvFile, pabBufAligned, cbBuf);
319338 if (cb > 0)
320 MD5Update(&Ctx, (unsigned char *)&abBuf[0], cb);
339 MD5Update(&Ctx, (unsigned char *)pabBufAligned, cb);
321340 else if (!cb)
322341 break;
323342 else
347366 if (fProgress)
348367 printf("\b\b\b\b \b\b\b\b");
349368
369 free(pabBuf);
350370 return rc;
351371 }
352372
570590 void *pvFile;
571591
572592 /*
573 * Calcuate and print the MD5 sum for one file.
593 * Calculate and print the MD5 sum for one file.
574594 */
575595 pvFile = open_file(pszFilename, fText);
576596 if (pvFile)
0 /* $Id: redirect.c 2839 2016-08-25 21:46:44Z bird $ */
0 /* $Id: redirect.c 2916 2016-09-15 11:41:42Z bird $ */
11 /** @file
22 * kmk_redirect - Do simple program <-> file redirection (++).
33 */
2828 #ifdef __APPLE__
2929 # define _POSIX_C_SOURCE 1 /* 10.4 sdk and unsetenv */
3030 #endif
31 #include "config.h"
31 #include "make.h"
32 #include <assert.h>
3233 #include <stdio.h>
3334 #include <stdlib.h>
3435 #include <string.h>
3536 #include <errno.h>
3637 #include <fcntl.h>
38 #if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
39 # include <process.h>
40 #endif
3741 #if defined(_MSC_VER)
3842 # include <ctype.h>
3943 # include <io.h>
40 # include <direct.h>
41 # include <process.h>
4244 # include "quote_argv.h"
4345 #else
4446 # include <unistd.h>
47 # include <spawn.h>
48 #endif
49
50 #include <k/kDefs.h>
51 #include <k/kTypes.h>
52 #include "err.h"
53 #include "kbuild_version.h"
54 #include "kmkbuiltin.h"
55 #ifdef KMK
56 # ifdef KBUILD_OS_WINDOWS
57 # include "sub_proc.h"
58 # include "pathstuff.h"
59 # endif
60 # include "job.h"
61 # include "variable.h"
4562 #endif
4663
4764 #ifdef __OS2__
5269 # endif
5370 #endif
5471
55
56 /*********************************************************************************************************************************
57 * Global Variables *
58 *********************************************************************************************************************************/
59 /** Number of times the '-v' switch was seen. */
60 static unsigned g_cVerbosity = 0;
72 #if !defined(KBUILD_OS_WINDOWS) && !defined(KBUILD_OS_OS2)
73 # define USE_POSIX_SPAWN
74 #endif
75
76
77 /* String + strlen tuple. */
78 #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1
6179
6280
6381 #if defined(_MSC_VER)
105123
106124 static int usage(FILE *pOut, const char *argv0)
107125 {
126 argv0 = name(argv0);
108127 fprintf(pOut,
109 "usage: %s [-[rwa+tb]<fd> <file>] [-c<fd>] [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage] [-v] -- <program> [args]\n"
128 "usage: %s [-[rwa+tb]<fd> <file>] [-d<fd>=<src-fd>] [-c<fd>]\n"
129 " [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage]\n"
130 " [-v] -- <program> [args]\n"
110131 " or: %s --help\n"
111132 " or: %s --version\n"
112133 "\n"
115136 " i = stdin\n"
116137 " o = stdout\n"
117138 " e = stderr\n"
139 "\n"
140 "The -d switch duplicate the right hand file descriptor (src-fd) to the left\n"
141 "hand side one (fd).\n"
118142 "\n"
119143 "The -c switch will close the specified file descriptor.\n"
120144 "\n"
137161 "/usr/bin/env on steroids.\n"
138162 ,
139163 argv0, argv0, argv0);
140 return 1;
164 return 2;
141165 }
142166
143167
168 /**
169 * Decoded file descriptor operations.
170 */
171 typedef struct REDIRECTORDERS
172 {
173 enum {
174 kRedirectOrder_Invalid = 0,
175 kRedirectOrder_Close,
176 kRedirectOrder_Open,
177 kRedirectOrder_Dup,
178 } enmOrder;
179 /** The target file handle. */
180 int fdTarget;
181 /** The source file name, -1 on close only.
182 * This is an opened file if pszFilename is set. */
183 int fdSource;
184 /** Whether to remove the file on failure cleanup. */
185 int fRemoveOnFailure;
186 /** The open flags (for O_TEXT/O_BINARY) on windows. */
187 int fOpen;
188 /** The filename - NULL if close only. */
189 const char *pszFilename;
190 #ifndef USE_POSIX_SPAWN
191 /** Saved file descriptor. */
192 int fdSaved;
193 /** Saved flags. */
194 int fSaved;
195 #endif
196 } REDIRECTORDERS;
197
198
199 #ifdef _MSC_VER
200
201 /**
202 * Safe way of getting the OS handle of a file descriptor without triggering
203 * invalid parameter handling.
204 *
205 * @returns The handle value if open, INVALID_HANDLE_VALUE if not.
206 * @param fd The file descriptor in question.
207 */
208 static HANDLE mscGetOsHandle(int fd)
209 {
210 intptr_t hHandle;
211 _invalid_parameter_handler pfnOld = _get_invalid_parameter_handler();
212 _set_invalid_parameter_handler(ignore_invalid_parameter);
213 hHandle = _get_osfhandle(fd);
214 _set_invalid_parameter_handler(pfnOld);
215 return hHandle != -1 ? (HANDLE)hHandle : INVALID_HANDLE_VALUE;
216 }
217
218 /**
219 * Checks if the specified file descriptor is open.
220 *
221 * @returns K_TRUE if open, K_FALSE if not.
222 * @param fd The file descriptor in question.
223 */
224 static KBOOL mscIsOpenFile(int fd)
225 {
226 return mscGetOsHandle(fd) != INVALID_HANDLE_VALUE;
227 }
228
229 /**
230 * Checks if the native handle is inheritable.
231 *
232 * @returns K_TRUE if it is, K_FALSE if it isn't or isn't a valid handle.
233 * @param hHandle The native handle.
234 */
235 static KBOOL mscIsNativeHandleInheritable(HANDLE hHandle)
236 {
237 DWORD fFlags = 0;
238 if (GetHandleInformation(hHandle, &fFlags))
239 return (fFlags & HANDLE_FLAG_INHERIT) != 0;
240 return K_FALSE;
241 }
242
243 /**
244 * Checks if the file descriptor is inheritable or not.
245 *
246 * @returns K_TRUE if it is, K_FALSE if it isn't or isn't a valid descriptor.
247 * @param fd The file descriptor in question.
248 */
249 static KBOOL mscIsInheritable(int fd)
250 {
251 HANDLE hHandle = mscGetOsHandle(fd);
252 if (hHandle != INVALID_HANDLE_VALUE)
253 return mscIsNativeHandleInheritable(hHandle);
254 return K_FALSE;
255 }
256
257 /**
258 * A dup3 like function.
259 *
260 * @returns fdNew on success, -1 on failure w/ error details written to pStdErr.
261 * @param fdSource The source descriptor.
262 * @param fdNew The new descriptor.
263 * @param fFlags The inherit and text/binary mode flag.
264 * @param pStdErr Working stderr to write error details to.
265 */
266 static int mscDup3(int fdSource, int fdNew, int fFlags, FILE *pStdErr)
267 {
268 if (!fFlags & _O_NOINHERIT)
269 {
270 /* ASSUMES fFlags doesn't include any changing _O_TEXT/_O_BINARY. */
271 int fdDup = _dup2(fdSource, fdNew);
272 if (fdDup != -1)
273 return fdDup;
274 fprintf(pStdErr, "%s: _dup2(%d,%d) failed: %s\n", g_progname, fdSource, fdNew, strerror(errno));
275 }
276 else
277 {
278 HANDLE hSource = mscGetOsHandle(fdSource);
279 unsigned cTries = 0;
280 int aFdTries[48];
281
282 if (hSource != INVALID_HANDLE_VALUE)
283 {
284 HANDLE hCurProc = GetCurrentProcess();
285 BOOL fInherit = !(fFlags & _O_NOINHERIT);
286
287 /*
288 * Make sure the old descriptor is closed and can be used again.
289 */
290 _invalid_parameter_handler pfnOld = _get_invalid_parameter_handler();
291 _set_invalid_parameter_handler(ignore_invalid_parameter);
292 close(fdNew);
293 _set_invalid_parameter_handler(pfnOld);
294
295 /*
296 * Duplicate the source handle till we've got a match.
297 */
298 for (;;)
299 {
300 HANDLE hDup = INVALID_HANDLE_VALUE;
301 if (DuplicateHandle(hCurProc, hSource, hCurProc, &hDup, 0 /* DesiredAccess */,
302 fInherit, DUPLICATE_SAME_ACCESS))
303 {
304 int fdDup = _open_osfhandle((intptr_t)hDup, fFlags);
305 if (fdDup != -1)
306 {
307 if (fdDup == fdNew)
308 {
309 while (cTries-- > 0)
310 close(aFdTries[cTries]);
311 return fdDup;
312 }
313
314 aFdTries[cTries++] = fdDup;
315 if ( fdDup < fdNew
316 && cTries < K_ELEMENTS(aFdTries))
317 continue;
318 fprintf(pStdErr, "%s: mscDup3(%d,%d): giving up! (last fdDup=%d)\n",
319 g_progname, fdSource, fdNew, fdDup);
320 }
321 else
322 {
323 fprintf(pStdErr, "%s: _open_osfhandle(%#x) failed: %u\n", g_progname, hDup, strerror(errno));
324 CloseHandle(hDup);
325 }
326 }
327 else
328 fprintf(pStdErr, "%s: DuplicateHandle(%#x) failed: %u\n", g_progname, hSource, GetLastError());
329 break;
330 }
331
332 while (cTries-- > 0)
333 close(aFdTries[cTries]);
334 }
335 else
336 fprintf(pStdErr, "%s: mscDup3(%d,%d): source descriptor is invalid!\n", g_progname, fdSource, fdNew);
337 }
338 return -1;
339 }
340
341 #endif /* _MSC_VER */
342
343 static KBOOL kRedirectHasConflict(int fd, unsigned cOrders, REDIRECTORDERS *paOrders)
344 {
345 while (cOrders-- > 0)
346 if (paOrders[cOrders].fdTarget == fd)
347 return K_TRUE;
348 return K_FALSE;
349 }
350
351
352 /**
353 * Creates a file descriptor for @a pszFilename that does not conflict with any
354 * previous orders.
355 *
356 * We need to be careful that there isn't a close or dup targetting the
357 * temporary file descriptor we return. Also, we need to take care with the
358 * descriptor's inheritability. It should only be inheritable if the returned
359 * descriptor matches the target descriptor (@a fdTarget).
360 *
361 * @returns File descriptor on success, -1 & err/errx on failure.
362 *
363 * The returned file descriptor is not inherited (i.e. close-on-exec),
364 * unless it matches @a fdTarget
365 *
366 * @param pszFilename The filename to open.
367 * @param fOpen The open flags.
368 * @param fMode The file creation mode (if applicable).
369 * @param cOrders The number of orders.
370 * @param paOrders The order array.
371 * @param fRemoveOnFailure Whether to remove the file on failure.
372 * @param fdTarget The target descriptor.
373 */
374 static int kRedirectOpenWithoutConflict(const char *pszFilename, int fOpen, mode_t fMode,
375 unsigned cOrders, REDIRECTORDERS *paOrders, int fRemoveOnFailure, int fdTarget)
376 {
377 #ifdef _O_NOINHERIT
378 int const fNoInherit = _O_NOINHERIT;
379 #elif defined(O_NOINHERIT)
380 int const fNoInherit = O_NOINHERIT;
381 #elif defined(O_CLOEXEC)
382 int const fNoInherit = O_CLOEXEC;
383 #else
384 # error "port me"
385 #endif
386 int aFdTries[32];
387 int cTries;
388 int fdOpened;
389
390 #ifdef KBUILD_OS_WINDOWS
391 if (strcmp(pszFilename, "/dev/null") == 0)
392 pszFilename = "nul";
393 #endif
394
395 /* Open it first. */
396 fdOpened = open(pszFilename, fOpen | fNoInherit, fMode);
397 if (fdOpened < 0)
398 return err(-1, "open(%s,%#x,) failed", pszFilename, fOpen);
399
400 /* Check for conflicts. */
401 if (!kRedirectHasConflict(fdOpened, cOrders, paOrders))
402 {
403 if (fdOpened != fdTarget)
404 return fdOpened;
405 #ifndef _MSC_VER /* Stupid, stupid MSVCRT! No friggin way of making a handle inheritable (or not). */
406 if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) != -1)
407 return fdOpened;
408 #endif
409 }
410
411 /*
412 * Do conflict resolving.
413 */
414 cTries = 1;
415 aFdTries[cTries++] = fdOpened;
416 while (cTries < K_ELEMENTS(aFdTries))
417 {
418 fdOpened = open(pszFilename, fOpen | fNoInherit, fMode);
419 if (fdOpened >= 0)
420 {
421 if ( !kRedirectHasConflict(fdOpened, cOrders, paOrders)
422 #ifdef _MSC_VER
423 && fdOpened != fdTarget
424 #endif
425 )
426 {
427 #ifndef _MSC_VER
428 if ( fdOpened != fdTarget
429 || fcntl(fdOpened, F_SETFD, FD_CLOEXEC) != -1)
430 #endif
431 {
432 while (cTries-- > 0)
433 close(aFdTries[cTries]);
434 return fdOpened;
435 }
436 }
437
438 }
439 else
440 {
441 err(-1, "open(%s,%#x,) #%u failed", pszFilename, cTries + 1, fOpen);
442 break;
443 }
444 aFdTries[cTries++] = fdOpened;
445 }
446
447 /*
448 * Give up.
449 */
450 if (fdOpened >= 0)
451 errx(-1, "failed to find a conflict free file descriptor for '%s'!", pszFilename);
452
453 while (cTries-- > 0)
454 close(aFdTries[cTries]);
455 return -1;
456 }
457
458 #ifndef USE_POSIX_SPAWN
459
460 /**
461 * Saves a file handle to one which isn't inherited and isn't affected by the
462 * file orders.
463 *
464 * @returns 0 on success, non-zero exit code on failure.
465 * @param pToSave Pointer to the file order to save the target
466 * descriptor of.
467 * @param cOrders Number of file orders.
468 * @param paOrders The array of file orders.
469 * @param ppWorkingStdErr Pointer to a pointer to a working stderr. This will
470 * get replaced if we're saving stderr, so that we'll
471 * keep having a working one to report failures to.
472 */
473 static int kRedirectSaveHandle(REDIRECTORDERS *pToSave, unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
474 {
475 int fdToSave = pToSave->fdTarget;
476 int rcRet = 10;
477
478 /*
479 * First, check if there's actually handle here that needs saving.
480 */
481 # ifdef KBUILD_OS_WINDOWS
482 HANDLE hToSave = mscGetOsHandle(fdToSave);
483 if (hToSave != INVALID_HANDLE_VALUE)
484 {
485 pToSave->fSaved = _setmode(fdToSave, _O_BINARY);
486 if (pToSave->fSaved != _O_BINARY)
487 _setmode(fdToSave, pToSave->fSaved);
488 if (!mscIsNativeHandleInheritable(hToSave))
489 pToSave->fSaved |= _O_NOINHERIT;
490 }
491 if (hToSave != INVALID_HANDLE_VALUE)
492 # else
493 pToSave->fSaved = fcntl(pToSave->fdTarget, F_GETFD, 0);
494 if (pToSave->fSaved != -1)
495 # endif
496 {
497 /*
498 * Try up to 32 times to get a duplicate descriptor that doesn't conflict.
499 */
500 # ifdef KBUILD_OS_WINDOWS
501 HANDLE hCurProc = GetCurrentProcess();
502 # endif
503 int aFdTries[32];
504 int cTries = 0;
505 do
506 {
507 /* Duplicate the handle (windows makes this complicated). */
508 int fdDup;
509 # ifdef KBUILD_OS_WINDOWS
510 HANDLE hDup = INVALID_HANDLE_VALUE;
511 if (!DuplicateHandle(hCurProc, hToSave, hCurProc, &hDup, 0 /* DesiredAccess */,
512 FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
513 {
514 fprintf(*ppWorkingStdErr, "%s: DuplicateHandle(%#x) failed: %u\n", g_progname, hToSave, GetLastError());
515 break;
516 }
517 fdDup = _open_osfhandle((intptr_t)hDup, pToSave->fSaved | _O_NOINHERIT);
518 if (fdDup == -1)
519 {
520 fprintf(*ppWorkingStdErr, "%s: _open_osfhandle(%#x) failed: %u\n", g_progname, hDup, strerror(errno));
521 CloseHandle(hDup);
522 break;
523 }
524 # else
525 fdDup = dup(fdToSave);
526 if (fdDup == -1)
527 {
528 fprintf(*ppWorkingStdErr, "%s: dup(%#x) failed: %u\n", g_progname, fdToSave, strerror(errno));
529 break;
530 }
531 #endif
532 /* Is the duplicate usable? */
533 if (!kRedirectHasConflict(fdDup, cOrders, paOrders))
534 {
535 pToSave->fdSaved = fdDup;
536 if ( *ppWorkingStdErr == stderr
537 && fdToSave == fileno(*ppWorkingStdErr))
538 {
539 *ppWorkingStdErr = fdopen(fdDup, "wt");
540 if (*ppWorkingStdErr == NULL)
541 {
542 fprintf(stderr, "%s: fdopen(%d,\"wt\") failed: %s\n", g_progname, fdDup, strerror(errno));
543 *ppWorkingStdErr = stderr;
544 close(fdDup);
545 break;
546 }
547 }
548 rcRet = 0;
549 break;
550 }
551
552 /* Not usuable, stash it and try again. */
553 aFdTries[cTries++] = fdDup;
554 } while (cTries < K_ELEMENTS(aFdTries));
555
556 /*
557 * Clean up unused duplicates.
558 */
559 while (cTries-- > 0)
560 close(aFdTries[cTries]);
561 }
562 else
563 {
564 /*
565 * Nothing to save.
566 */
567 pToSave->fdSaved = -1;
568 rcRet = 0;
569 }
570 return rcRet;
571 }
572
573
574 /**
575 * Cleans up the file operation orders.
576 *
577 * This does not restore stuff, just closes handles we've opened for the guest.
578 *
579 * @param cOrders Number of file operation orders.
580 * @param paOrders The file operation orders.
581 * @param fFailed Set if it's a failure.
582 */
583 static void kRedirectCleanupFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, KBOOL fFailure)
584 {
585 unsigned i = cOrders;
586 while (i-- > 0)
587 {
588 if ( paOrders[i].enmOrder == kRedirectOrder_Open
589 && paOrders[i].fdSource != -1)
590 {
591 close(paOrders[i].fdSource);
592 paOrders[i].fdSource = -1;
593 if ( fFailure
594 && paOrders[i].fRemoveOnFailure
595 && paOrders[i].pszFilename)
596 remove(paOrders[i].pszFilename);
597 }
598 }
599 }
600
601
602 /**
603 * Restores the target file descriptors affected by the file operation orders.
604 *
605 * @param cOrders Number of file operation orders.
606 * @param paOrders The file operation orders.
607 * @param ppWorkingStdErr Pointer to a pointer to the working stderr. If this
608 * is one of the saved file descriptors, we'll restore
609 * it to stderr.
610 */
611 static void kRedirectRestoreFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
612 {
613 int iSavedErrno = errno;
614 unsigned i = cOrders;
615 while (i-- > 0)
616 {
617 if (paOrders[i].fdSaved != -1)
618 {
619 KBOOL fRestoreStdErr = *ppWorkingStdErr != stderr
620 && paOrders[i].fdSaved == fileno(*ppWorkingStdErr);
621
622 #ifdef KBUILD_OS_WINDOWS
623 if (mscDup3(paOrders[i].fdSaved, paOrders[i].fdTarget, paOrders[i].fSaved, *ppWorkingStdErr) != -1)
624 #else
625 if (dup2(paOrders[i].fdSaved, paOrders[i].fdTarget) != -1)
626 #endif
627 {
628 close(paOrders[i].fdSaved);
629 paOrders[i].fdSaved = -1;
630
631 if (fRestoreStdErr)
632 {
633 *ppWorkingStdErr = stderr;
634 assert(fileno(stderr) == paOrders[i].fdTarget);
635 }
636 }
637 #ifndef KBUILD_OS_WINDOWS
638 else
639 fprintf(*ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s",
640 g_progname, paOrders[i].fdSaved, paOrders[i].fdTarget, strerror(errno));
641 #endif
642 }
643
644 #ifndef KBUILD_OS_WINDOWS
645 if (paOrders[i].fSaved != -1)
646 {
647 if (fcntl(paOrders[i].fdTarget, F_SETFD, paOrders[i].fSaved & FD_CLOEXEC) == -1)
648 paOrders[i].fSaved = -1;
649 else
650 fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,%s) failed: %s",
651 g_progname, paOrders[i].fdTarget, paOrders[i].fSaved & FD_CLOEXEC ? "FD_CLOEXEC" : "0", strerror(errno));
652 }
653 #endif
654 }
655 errno = iSavedErrno;
656 }
657
658
659 /**
660 * Executes the file operation orders.
661 *
662 * @returns 0 on success, exit code on failure.
663 * @param cOrders Number of file operation orders.
664 * @param paOrders File operation orders to execute.
665 * @param ppWorkingStdErr Where to return a working stderr (mainly for
666 * kRedirectRestoreFdOrders).
667 */
668 static int kRedirectExecFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
669 {
670 unsigned i;
671
672 *ppWorkingStdErr = stderr;
673 for (i = 0; i < cOrders; i++)
674 {
675 int rcExit = 10;
676 switch (paOrders[i].enmOrder)
677 {
678 case kRedirectOrder_Close:
679 {
680 /* If the handle isn't used by any of the following operation,
681 just mark it as non-inheritable if necessary. */
682 int const fdTarget = paOrders[i].fdTarget;
683 unsigned j;
684 for (j = i + 1; j < cOrders; j++)
685 if (paOrders[j].fdTarget == fdTarget)
686 break;
687 # ifdef _MSC_VER
688 if (j >= cOrders && !mscIsInheritable(fdTarget))
689 rcExit = 0;
690 # else
691 if (j >= cOrders)
692 {
693 paOrders[j].fSaved = fcntl(fdTarget, F_GETFD, 0);
694 if (paOrders[j].fSaved != -1)
695 {
696 if (paOrders[j].fSaved & FD_CLOEXEC)
697 rcExit = 0;
698 else if ( fcntl(fdTarget, F_SETFD, FD_CLOEXEC) != -1
699 || errno == EBADF)
700 rcExit = 0;
701 else
702 fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,FD_CLOEXEC) failed: %s",
703 g_progname, fdTarget, strerror(errno));
704 }
705 else if (errno == EBADF)
706 rcExit = 0;
707 else
708 fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_GETFD,0) failed: %s", g_progname, fdTarget, strerror(errno));
709 }
710 # endif
711 else
712 rcExit = kRedirectSaveHandle(&paOrders[i], cOrders, paOrders, ppWorkingStdErr);
713 break;
714 }
715
716 case kRedirectOrder_Dup:
717 case kRedirectOrder_Open:
718 rcExit = kRedirectSaveHandle(&paOrders[i], cOrders, paOrders, ppWorkingStdErr);
719 if (rcExit == 0)
720 {
721 if (dup2(paOrders[i].fdSource, paOrders[i].fdTarget) != -1)
722 rcExit = 0;
723 else
724 {
725 if (paOrders[i].enmOrder == kRedirectOrder_Open)
726 fprintf(*ppWorkingStdErr, "%s: dup2(%d [%s],%d) failed: %s", g_progname, paOrders[i].fdSource,
727 paOrders[i].pszFilename, paOrders[i].fdTarget, strerror(errno));
728 else
729 fprintf(*ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s",
730 g_progname, paOrders[i].fdSource, paOrders[i].fdTarget, strerror(errno));
731 rcExit = 10;
732 }
733 }
734 break;
735
736 default:
737 fprintf(*ppWorkingStdErr, "%s: error! invalid enmOrder=%d\n", g_progname, paOrders[i].enmOrder);
738 rcExit = 99;
739 break;
740 }
741
742 if (rcExit != 0)
743 {
744 kRedirectRestoreFdOrders(i, paOrders, ppWorkingStdErr);
745 return rcExit;
746 }
747 }
748
749 return 0;
750 }
751
752 #endif /* !USE_POSIX_SPAWN */
753
754
755 /**
756 * Does the child spawning .
757 *
758 * @returns Exit code.
759 * @param pszExecutable The child process executable.
760 * @param cArgs Number of arguments.
761 * @param papszArgs The child argument vector.
762 * @param fWatcomBrainDamage Whether MSC need to do quoting according to
763 * weird Watcom WCC rules.
764 * @param papszEnv The child environment vector.
765 * @param pszCwd The current working directory of the child.
766 * @param pszSavedCwd The saved current working directory. This is
767 * NULL if the CWD doesn't need changing.
768 * @param cOrders Number of file operation orders.
769 * @param paOrders The file operation orders.
770 * @param pFileActions The posix_spawn file actions.
771 * @param cVerbosity The verbosity level.
772 * @param pPidSpawned Where to return the PID of the spawned child
773 * when we're inside KMK and we're return without
774 * waiting.
775 * @param pfIsChildExitCode Where to indicate whether the return exit code
776 * is from the child or from our setup efforts.
777 */
778 static int kRedirectDoSpawn(const char *pszExecutable, int cArgs, char **papszArgs, int fWatcomBrainDamage, char **papszEnv,
779 const char *pszCwd, const char *pszSavedCwd, unsigned cOrders, REDIRECTORDERS *paOrders,
780 #ifdef USE_POSIX_SPAWN
781 posix_spawn_file_actions_t *pFileActions,
782 #endif
783 unsigned cVerbosity,
784 #ifdef KMK
785 pid_t *pPidSpawned,
786 #endif
787 KBOOL *pfIsChildExitCode)
788 {
789 int rcExit;
790 int i;
791 #ifdef _MSC_VER
792 char **papszArgsOriginal = papszArgs;
793 #endif
794 *pfIsChildExitCode = K_FALSE;
795
796 #ifdef _MSC_VER
797 /*
798 * Do MSC parameter quoting.
799 */
800 papszArgs = malloc((cArgs + 1) * sizeof(papszArgs[0]));
801 if (papszArgs)
802 memcpy(papszArgs, papszArgsOriginal, (cArgs + 1) * sizeof(papszArgs[0]));
803 else
804 return errx(9, "out of memory!");
805
806 rcExit = quote_argv(cArgs, papszArgs, fWatcomBrainDamage, 0 /*fFreeOrLeak*/);
807 if (rcExit == 0)
808 #endif
809 {
810 /*
811 * Display what we're about to execute if we're in verbose mode.
812 */
813 if (cVerbosity > 0)
814 {
815 for (i = 0; i < cArgs; i++)
816 warnx("debug: argv[%i]=%s<eos>", i, papszArgs[i]);
817 for (i = 0; i < (int)cOrders; i++)
818 switch (paOrders[i].enmOrder)
819 {
820 case kRedirectOrder_Close:
821 warnx("debug: close %d\n", paOrders[i].fdTarget);
822 break;
823 case kRedirectOrder_Dup:
824 warnx("debug: dup %d to %d\n", paOrders[i].fdSource, paOrders[i].fdTarget);
825 break;
826 case kRedirectOrder_Open:
827 warnx("debug: open '%s' (%#x) as [%d ->] %d\n",
828 paOrders[i].pszFilename, paOrders[i].fOpen, paOrders[i].fdSource, paOrders[i].fdTarget);
829 break;
830 default:
831 warnx("error! invalid enmOrder=%d", paOrders[i].enmOrder);
832 assert(0);
833 break;
834 }
835 if (pszSavedCwd)
836 warnx("debug: chdir %s\n", pszCwd);
837 }
838
839 /*
840 * Change working directory if so requested.
841 */
842 if (pszSavedCwd)
843 {
844 if (chdir(pszCwd) < 0)
845 rcExit = errx(10, "Failed to change directory to '%s'", pszCwd);
846 }
847 if (rcExit == 0)
848 {
849 #ifndef USE_POSIX_SPAWN
850 /*
851 * Execute the file orders.
852 */
853 FILE *pWorkingStdErr = NULL;
854 rcExit = kRedirectExecFdOrders(cOrders, paOrders, &pWorkingStdErr);
855 if (rcExit == 0)
856 #endif
857 {
858 #ifdef KMK
859 /*
860 * We're spawning from within kmk.
861 */
862 #if defined(KBUILD_OS_WINDOWS)
863 /* Windows is slightly complicated due to handles and sub_proc.c. */
864 HANDLE hProcess = (HANDLE)_spawnvpe(_P_NOWAIT, pszExecutable, papszArgs, papszEnv);
865 kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
866 if ((intptr_t)hProcess != -1)
867 {
868 if (process_kmk_register_redirect(hProcess, pPidSpawned) == 0)
869 {
870 if (cVerbosity > 0)
871 warnx("debug: spawned %d", *pPidSpawned);
872 }
873 else
874 {
875 DWORD dwTmp;
876 warn("sub_proc is out of slots, waiting for child...");
877 dwTmp = WaitForSingleObject(hProcess, INFINITE);
878 if (dwTmp != WAIT_OBJECT_0)
879 warn("WaitForSingleObject failed: %#x\n", dwTmp);
880
881 if (GetExitCodeProcess(hProcess, &dwTmp))
882 rcExit = (int)dwTmp;
883 else
884 {
885 warn("GetExitCodeProcess failed: %u\n", GetLastError());
886 TerminateProcess(hProcess, 127);
887 rcExit = 127;
888 }
889
890 CloseHandle(hProcess);
891 *pPidSpawned = 0;
892 *pfIsChildExitCode = K_TRUE;
893 }
894 }
895 else
896 rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
897
898 # elif defined(KBUILD_OS_OS2)
899 *pPidSpawned = _spawnve(_P_NOWAIT, pszExecutable, papszArgs, papszEnv);
900 kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
901 if (*pPidSpawned != -1)
902 {
903 if (cVerbosity > 0)
904 warnx("debug: spawned %d", *pPidSpawned);
905 }
906 else
907 {
908 rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
909 *pPidSpawned = 0;
910 }
911 #else
912 rcExit = posix_spawnp(pPidSpawned, pszExecutable, pFileActions, NULL /*pAttr*/, papszArgs, papszEnvVars);
913 if (rcExit == 0)
914 {
915 if (cVerbosity > 0)
916 warnx("debug: spawned %d", *pPidSpawned);
917 }
918 else
919 {
920 rcExit = errx(10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
921 *pPidSpawned = 0;
922 }
923 #endif
924
925 #else /* !KMK */
926 /*
927 * Spawning from inside the kmk_redirect executable.
928 */
929 # if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
930 errno = 0;
931 rcExit = (int)_spawnvpe(_P_WAIT, pszExecutable, papszArgs, papszEnv);
932 kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
933 if (rcExit != -1 || errno == 0)
934 {
935 *pfIsChildExitCode = K_TRUE;
936 if (cVerbosity > 0)
937 warnx("debug: exit code: %d", rcExit);
938 }
939 else
940 rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
941
942 # else
943 pid_t pidChild = 0;
944 rcExit = posix_spawnp(&pidChild, pszExecutable, pFileActions, NULL /*pAttr*/, papszArgs, papszEnvVars);
945 if (rcExit == 0)
946 {
947 *pfIsChildExitCode = K_TRUE;
948 if (cVerbosity > 0)
949 warnx("debug: spawned %d", pidChild);
950
951 /* Wait for the child. */
952 for (;;)
953 {
954 pid_t pid = waitpid(pidChild, &rcExit, 0 /*block*/);
955 if (pid == pidChild)
956 {
957 if (cVerbosity > 0)
958 warnx("debug: %d exit code: %d", pidChild, rcExit);
959 break;
960 }
961 if ( errno != EINTR
962 # ifdef ERESTART
963 && errno != ERESTART
964 # endif
965 )
966 {
967 rcExit = err(11, "waitpid failed");
968 kill(pidChild, SIGKILL);
969 break;
970 }
971 }
972 }
973 else
974 rcExit = errx(10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
975
976 # endif
977 #endif /* !KMK */
978 }
979 }
980
981 /*
982 * Restore the current directory.
983 */
984 if (pszSavedCwd)
985 {
986 if (chdir(pszSavedCwd) < 0)
987 warn("Failed to restore directory to '%s'", pszSavedCwd);
988 }
989 }
990 #ifdef _MSC_VER
991 else
992 rcExit = errx(9, "quite_argv failed: %u", rcExit);
993
994 /* Restore the original argv strings, freeing the quote_argv replacements. */
995 i = cArgs;
996 while (i-- > 0)
997 if (papszArgs[i] != papszArgsOriginal[i])
998 free(papszArgs[i]);
999 free(papszArgs);
1000 #endif
1001 return rcExit;
1002 }
1003
1004
1005 /**
1006 * The function that does almost everything here... ugly.
1007 */
1008 #ifdef KMK
1009 int kmk_builtin_redirect(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned)
1010 #else
1441011 int main(int argc, char **argv, char **envp)
145 {
146 int i;
147 int j;
148 #if defined(_MSC_VER)
149 intptr_t rc;
150 #endif
151 FILE *pStdErr = stderr;
152 FILE *pStdOut = stdout;
153 int fWatcomBrainDamage = 0;
1012 #endif
1013 {
1014 int rcExit = 0;
1015 KBOOL fChildExitCode = K_FALSE;
1016 #ifdef USE_POSIX_SPAWN
1017 posix_spawn_file_actions_t FileActions;
1018 #endif
1019 unsigned cOrders = 0;
1020 REDIRECTORDERS aOrders[32];
1021
1022 int iArg;
1023 const char *pszExecutable = NULL;
1024 char **papszEnv = NULL;
1025 unsigned cAllocatedEnvVars;
1026 unsigned iEnvVar;
1027 unsigned cEnvVars;
1028 int fWatcomBrainDamage = 0;
1029 int cVerbosity = 0;
1030 char *pszSavedCwd = NULL;
1031 size_t const cbCwdBuf = GET_PATH_MAX;
1032 PATH_VAR(szCwd);
1033 #ifdef KBUILD_OS_OS2
1034 ULONG ulLibPath;
1035 char *apszSavedLibPaths[LIBPATHSTRICT + 1] = { NULL, NULL, NULL, NULL };
1036 #endif
1037
1038
1039 g_progname = argv[0];
1040
1041 if (argc <= 1)
1042 return usage(stderr, argv[0]);
1043
1044 /*
1045 * Create default program environment.
1046 */
1047 #if defined(KMK) && defined(KBUILD_OS_WINDOWS)
1048 if (getcwd_fs(szCwd, cbCwdBuf) != NULL)
1049 #else
1050 if (getcwd(szCwd, cbCwdBuf) != NULL)
1051 #endif
1052 { /* likely */ }
1053 else
1054 return err(9, "getcwd failed");
1055
1056 #if defined(KMK)
1057 /* We get it from kmk and just count it: */
1058 papszEnv = pChild->environment;
1059 if (!papszEnv)
1060 pChild->environment = papszEnv = target_environment(pChild->file);
1061 cEnvVars = 0;
1062 while (papszEnv[cEnvVars] != NULL)
1063 cEnvVars++;
1064 cAllocatedEnvVars = cEnvVars;
1065 #else
1066 /* We make a copy and we manage ourselves: */
1067 cEnvVars = 0;
1068 while (envp[cEnvVars] != NULL)
1069 cEnvVars++;
1070
1071 cAllocatedEnvVars = cEnvVars + 4;
1072 papszEnv = malloc((cAllocatedEnvVars + 1) * sizeof(papszEnv));
1073 if (!papszEnv)
1074 return errx(9, "out of memory!");
1075
1076 iEnvVar = cEnvVars;
1077 papszEnv[iEnvVar] = NULL;
1078 while (iEnvVar-- > 0)
1079 {
1080 papszEnv[iEnvVar] = strdup(envp[iEnvVar]);
1081 if (!papszEnv[iEnvVar])
1082 {
1083 while (iEnvVar-- > 0)
1084 free(papszEnv[iEnvVar]);
1085 free(papszEnv);
1086 return errx(9, "out of memory!");
1087 }
1088 }
1089 #endif
1090
1091 #ifdef USE_POSIX_SPAWN
1092 /*
1093 * Init posix attributes.
1094 */
1095 rcExit = posix_spawn_file_actions_init(&FileActions);
1096 if (rcExit != 0)
1097 rcExit = errx(9, "posix_spawn_file_actions_init failed: %s", strerror(rcExit));
1098 #endif
1541099
1551100 /*
1561101 * Parse arguments.
1571102 */
158 if (argc <= 1)
159 return usage(pStdErr, name(argv[0]));
160 for (i = 1; i < argc; i++)
1103 for (iArg = 1; rcExit == 0 && iArg < argc; iArg++)
1611104 {
162 if (argv[i][0] == '-')
1105 char *pszArg = argv[iArg];
1106 if (*pszArg == '-')
1631107 {
164 int fd;
165 int fdOpened;
166 int fOpen;
167 char *psz = &argv[i][1];
168 if (*psz == '-')
169 {
170 /* '--' ? */
171 if (!psz[1])
172 {
173 i++;
1108 int fd;
1109 char chOpt;
1110 const char *pszValue;
1111
1112 chOpt = *++pszArg;
1113 pszArg++;
1114 if (chOpt == '-')
1115 {
1116 /* '--' indicates where the bits to execute start. */
1117 if (*pszArg == '\0')
1118 {
1119 iArg++;
1741120 break;
1751121 }
1761122
177 /* convert to short. */
178 if (!strcmp(psz, "-help"))
179 psz = "h";
180 else if (!strcmp(psz, "-version"))
181 psz = "V";
182 else if (!strcmp(psz, "-env"))
183 psz = "E";
184 else if (!strcmp(psz, "-chdir"))
185 psz = "C";
186 else if (!strcmp(psz, "-zap-env"))
187 psz = "Z";
188 else if (!strcmp(psz, "-close"))
189 psz = "c";
190 else if (!strcmp(psz, "-wcc-brain-damage"))
1123 if ( strcmp(pszArg, "wcc-brain-damage") == 0
1124 || strcmp(pszArg, "watcom-brain-damage") == 0)
1911125 {
1921126 fWatcomBrainDamage = 1;
1931127 continue;
1941128 }
1129
1130 /* convert to short. */
1131 if (strcmp(pszArg, "help") == 0)
1132 chOpt = 'h';
1133 else if (strcmp(pszArg, "version") == 0)
1134 chOpt = 'V';
1135 else if ( strcmp(pszArg, "set") == 0
1136 || strcmp(pszArg, "env") == 0)
1137 chOpt = 'E';
1138 else if (strcmp(pszArg, "unset") == 0)
1139 chOpt = 'U';
1140 else if ( strcmp(pszArg, "zap-env") == 0
1141 || strcmp(pszArg, "ignore-environment") == 0 /* GNU env compatibility. */ )
1142 chOpt = 'Z';
1143 else if (strcmp(pszArg, "chdir") == 0)
1144 chOpt = 'C';
1145 else if (strcmp(pszArg, "close") == 0)
1146 chOpt = 'c';
1147 else if (strcmp(pszArg, "verbose") == 0)
1148 chOpt = 'v';
1149 else
1150 {
1151 errx(2, "Unknown option: '%s'", pszArg - 2);
1152 rcExit = usage(stderr, argv[0]);
1153 break;
1154 }
1155 pszArg = "";
1951156 }
1961157
1971158 /*
198 * Deal with the obligatory help and version switches first.
1159 * Deal with the obligatory help and version switches first to get them out of the way.
1991160 */
200 if (*psz == 'h')
201 {
202 usage(pStdOut, name(argv[0]));
203 return 0;
204 }
205 if (*psz == 'V')
206 {
207 printf("kmk_redirect - kBuild version %d.%d.%d (r%u)\n"
208 "Copyright (C) 2007-2012 knut st. osmundsen\n",
209 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
210 KBUILD_SVN_REV);
211 return 0;
212 }
1161 if (chOpt == 'h')
1162 {
1163 usage(stdout, argv[0]);
1164 rcExit = -1;
1165 break;
1166 }
1167 if (chOpt == 'V')
1168 {
1169 kbuild_version(argv[0]);
1170 rcExit = -1;
1171 break;
1172 }
1173
1174 /*
1175 * Get option value first, if the option takes one.
1176 */
1177 if ( chOpt == 'E'
1178 || chOpt == 'U'
1179 || chOpt == 'C'
1180 || chOpt == 'c'
1181 || chOpt == 'd'
1182 || chOpt == 'e')
1183 {
1184 if (*pszArg != '\0')
1185 pszValue = pszArg + (*pszArg == ':' || *pszArg == '=');
1186 else if (++iArg < argc)
1187 pszValue = argv[iArg];
1188 else
1189 {
1190 errx(2, "syntax error: Option -%c requires a value!", chOpt);
1191 rcExit = usage(stderr, argv[0]);
1192 break;
1193 }
1194 }
1195 else
1196 pszValue = NULL;
2131197
2141198 /*
2151199 * Environment switch?
2161200 */
217 if (*psz == 'E')
218 {
219 psz++;
220 if (*psz == ':' || *psz == '=')
221 psz++;
222 else
223 {
224 if (i + 1 >= argc)
1201 if (chOpt == 'E')
1202 {
1203 const char *pchEqual = strchr(pszValue, '=');
1204 #ifdef KBUILD_OS_OS2
1205 if ( strncmp(pszValue, TUPLE("BEGINLIBPATH=")) == 0
1206 || strncmp(pszValue, TUPLE("ENDLIBPATH=")) == 0
1207 || strncmp(pszValue, TUPLE("LIBPATHSTRICT=")) == 0)
1208 {
1209 ULONG ulVar = *pszValue == 'B' ? BEGIN_LIBPATH
1210 : *pszValue == 'E' ? END_LIBPATH
1211 : LIBPATHSTRICT;
1212 APIRET rc;
1213 if (apszSavedLibPaths[ulVar] == NULL)
2251214 {
226 fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
227 return 1;
1215 /* The max length is supposed to be 1024 bytes. */
1216 apszSavedLibPaths[ulVar] = calloc(1024 * 2);
1217 if (apszSavedLibPaths[ulVar])
1218 {
1219 rc = DosQueryExtLIBPATH(apszSavedLibPaths[ulVar], ulVar);
1220 if (rc)
1221 {
1222 rcExit = errx(9, "DosQueryExtLIBPATH(,%u) failed: %lu", ulVar, rc);
1223 free(apszSavedLibPaths[ulVar]);
1224 apszSavedLibPaths[ulVar] = NULL;
1225 }
1226 }
1227 else
1228 rcExit = errx(9, "out of memory!");
2281229 }
229 psz = argv[++i];
230 }
231 #ifdef __OS2__
232 if ( !strncmp(psz, "BEGINLIBPATH=", sizeof("BEGINLIBPATH=") - 1)
233 || !strncmp(psz, "ENDLIBPATH=", sizeof("ENDLIBPATH=") - 1)
234 || !strncmp(psz, "LIBPATHSTRICT=", sizeof("LIBPATHSTRICT=") - 1))
235 {
236 ULONG ulVar = *psz == 'B' ? BEGIN_LIBPATH
237 : *psz == 'E' ? END_LIBPATH
238 : LIBPATHSTRICT;
239 const char *pszVal = strchr(psz, '=') + 1;
240 APIRET rc = DosSetExtLIBPATH(pszVal, ulVar);
241 if (rc)
1230 if (rcExit == 0)
2421231 {
243 fprintf(pStdErr, "%s: error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu\n",
244 name(argv[0]), pszVal, pszVal - psz - 1, psz, ulVar, rc);
245 return 1;
1232 rc = DosSetExtLIBPATH(pchEqual + 1, ulVar);
1233 if (rc)
1234 rcExit = errx(9, "error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu",
1235 pchEqual, pchEqual - pszValue, pchEqual + 1, ulVar, rc);
2461236 }
247 }
248 else
249 #endif /* __OS2__ */
250 {
251 const char *pchEqual = strchr(psz, '=');
252 if (pchEqual && pchEqual[1] != '\0')
1237 continue;
1238 }
1239 #endif /* KBUILD_OS_OS2 */
1240
1241 /* We differ from kSubmit here and use putenv sematics. */
1242 if (pchEqual)
1243 {
1244 if (pchEqual[1] != '\0')
2531245 {
254 if (putenv(psz))
255 {
256 fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
257 return 1;
258 }
1246 rcExit = kBuiltinOptEnvSet(&papszEnv, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
1247 #ifdef KMK
1248 pChild->environment = papszEnv;
1249 #endif
2591250 }
2601251 else
2611252 {
262 size_t cchVar = pchEqual ? (size_t)(pchEqual - psz) : strlen(psz);
263 char *pszCopy = (char *)malloc(cchVar + 2);
264 memcpy(pszCopy, psz, cchVar);
265
266 #if defined(_MSC_VER) || defined(__OS2__)
267 pszCopy[cchVar] = '=';
268 pszCopy[cchVar + 1] = '\0';
269 if (putenv(pszCopy))
1253 char *pszCopy = strdup(pszValue);
1254 if (pszCopy)
2701255 {
271 fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
272 return 1;
1256 pszCopy[pchEqual - pszValue] = '\0';
1257 rcExit = kBuiltinOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszCopy);
1258 free(pszCopy);
2731259 }
274 #else
275 pszCopy[cchVar] = '\0';
276 if (unsetenv(pszCopy))
277 {
278 fprintf(pStdErr, "%s: error: unsetenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
279 return 1;
280 }
281 #endif
282 free(pszCopy);
1260 else
1261 rcExit = errx(1, "out of memory!");
2831262 }
284 }
1263 continue;
1264 }
1265 /* Simple unset. */
1266 chOpt = 'U';
1267 }
1268
1269 /*
1270 * Unset environment variable.
1271 */
1272 if (chOpt == 'U')
1273 {
1274 #ifdef KBUILD_OS_OS2
1275 if ( strcmp(pszValue, "BEGINLIBPATH") == 0
1276 || strcmp(pszValue, "ENDLIBPATH") == 0
1277 || strcmp(pszValue, "LIBPATHSTRICT") == 0)
1278 rcExit = errx(2, "error: '%s' cannot be unset, only set to an empty value using -E/--set.", pszValue);
1279 else
1280 #endif
1281 rcExit = kBuiltinOptEnvUnset(papszEnv, &cEnvVars, cVerbosity, pszValue);
1282 continue;
1283 }
1284
1285 /*
1286 * Zap environment switch?
1287 */
1288 if ( chOpt == 'Z'
1289 || chOpt == 'i' /* GNU env compatibility. */ )
1290 {
1291 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
1292 free(papszEnv[iEnvVar]);
1293 papszEnv[0] = NULL;
1294 cEnvVars = 0;
2851295 continue;
2861296 }
2871297
2881298 /*
2891299 * Change directory switch?
2901300 */
291 if (*psz == 'C')
292 {
293 psz++;
294 if (*psz == ':' || *psz == '=')
295 psz++;
1301 if (chOpt == 'C')
1302 {
1303 if (pszSavedCwd == NULL)
1304 pszSavedCwd = strdup(szCwd);
1305 if (pszSavedCwd)
1306 rcExit = kBuiltinOptChDir(szCwd, cbCwdBuf, pszValue);
2961307 else
297 {
298 if (i + 1 >= argc)
299 {
300 fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
301 return 1;
302 }
303 psz = argv[++i];
304 }
305 if (!chdir(psz))
306 continue;
307 #ifdef _MSC_VER
308 {
309 /* drop trailing slash if any. */
310 size_t cch = strlen(psz);
311 if ( cch > 2
312 && (psz[cch - 1] == '/' || psz[cch - 1] == '\\')
313 && psz[cch - 1] != ':')
314 {
315 int rc2;
316 char *pszCopy = strdup(psz);
317 do pszCopy[--cch] = '\0';
318 while ( cch > 2
319 && (pszCopy[cch - 1] == '/' || pszCopy[cch - 1] == '\\')
320 && pszCopy[cch - 1] != ':');
321 rc2 = chdir(pszCopy);
322 free(pszCopy);
323 if (!rc2)
324 continue;
325 }
326 }
327 #endif
328 fprintf(pStdErr, "%s: error: chdir(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
329 return 1;
330 }
331
332 /*
333 * Zap environment switch?
334 * This is a bit of a hack.
335 */
336 if (*psz == 'Z')
337 {
338 unsigned j = 0;
339 while (envp[j] != NULL)
340 j++;
341 while (j-- > 0)
342 {
343 char *pszEqual = strchr(envp[j], '=');
344 char *pszCopy;
345
346 if (pszEqual)
347 *pszEqual = '\0';
348 pszCopy = strdup(envp[j]);
349 if (pszEqual)
350 *pszEqual = '=';
351
352 #if defined(_MSC_VER) || defined(__OS2__)
353 putenv(pszCopy);
354 #else
355 unsetenv(pszCopy);
356 #endif
357 free(pszCopy);
358 }
1308 rcExit = err(9, "out of memory!");
3591309 continue;
3601310 }
1311
3611312
3621313 /*
3631314 * Verbose operation switch?
3641315 */
365 if (*psz == 'v')
366 {
367 g_cVerbosity++;
1316 if (chOpt == 'v')
1317 {
1318 cVerbosity++;
3681319 continue;
3691320 }
3701321
3711322 /*
372 * Close the specified file descriptor (no stderr/out/in aliases).
1323 * Executable image other than the first argument following '--'.
3731324 */
374 if (*psz == 'c')
375 {
376 psz++;
377 if (!*psz)
378 {
379 i++;
380 if (i >= argc)
1325 if (chOpt == 'e')
1326 {
1327 pszExecutable = pszValue;
1328 continue;
1329 }
1330
1331 /*
1332 * Okay, it is some file descriptor opearation. Make sure we've got room for it.
1333 */
1334 if (cOrders + 1 < K_ELEMENTS(aOrders))
1335 {
1336 aOrders[cOrders].fdTarget = -1;
1337 aOrders[cOrders].fdSource = -1;
1338 aOrders[cOrders].fOpen = 0;
1339 aOrders[cOrders].fRemoveOnFailure = 0;
1340 aOrders[cOrders].pszFilename = NULL;
1341 #ifndef USE_POSIX_SPAWN
1342 aOrders[cOrders].fdSaved = -1;
1343 #endif
1344 }
1345 else
1346 {
1347 rcExit = errx(2, "error: too many file actions (max: %d)", K_ELEMENTS(aOrders));
1348 break;
1349 }
1350
1351 if (chOpt == 'c')
1352 {
1353 /*
1354 * Close the specified file descriptor (no stderr/out/in aliases).
1355 */
1356 char *pszTmp;
1357 fd = (int)strtol(pszValue, &pszTmp, 0);
1358 if (pszTmp == pszValue || *pszTmp != '\0')
1359 rcExit = errx(2, "error: failed to convert '%s' to a number", pszValue);
1360 else if (fd < 0)
1361 rcExit = errx(2, "error: negative fd %d (%s)", fd, pszValue);
1362 else
1363 {
1364 aOrders[cOrders].enmOrder = kRedirectOrder_Close;
1365 aOrders[cOrders].fdTarget = fd;
1366 cOrders++;
1367 #ifdef USE_POSIX_SPAWN
1368 rcExit = posix_spawn_file_actions_addclose(&FileActions, fd);
1369 if (rcExit != 0)
1370 rcExit = errx(2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
1371 #endif
1372 }
1373 }
1374 else if (chOpt == 'd')
1375 {
1376 /*
1377 * Duplicate file handle. Value is fdTarget=fdSource
1378 */
1379 char *pszEqual;
1380 fd = (int)strtol(pszValue, &pszEqual, 0);
1381 if (pszEqual == pszValue)
1382 rcExit = errx(2, "error: failed to convert target descriptor of '-d %s' to a number", pszValue);
1383 else if (fd < 0)
1384 rcExit = errx(2, "error: negative target descriptor %d ('-d %s')", fd, pszValue);
1385 else if (*pszEqual != '=')
1386 rcExit = errx(2, "syntax error: expected '=' to follow target descriptor: '-d %s'", pszValue);
1387 else
1388 {
1389 char *pszEnd;
1390 int fdSource = (int)strtol(++pszEqual, &pszEnd, 0);
1391 if (pszEnd == pszEqual || *pszEnd != '\0')
1392 rcExit = errx(2, "error: failed to convert source descriptor of '-d %s' to a number", pszValue);
1393 else if (fdSource < 0)
1394 rcExit = errx(2, "error: negative source descriptor %d ('-d %s')", fdSource, pszValue);
1395 else
3811396 {
382 fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
383 return 1;
1397 aOrders[cOrders].enmOrder = kRedirectOrder_Dup;
1398 aOrders[cOrders].fdTarget = fd;
1399 aOrders[cOrders].fdSource = fdSource;
1400 cOrders++;
1401 #ifdef USE_POSIX_SPAWN
1402 rcExit = posix_spawn_file_actions_adddup2(&FileActions, fdSource, fd);
1403 if (rcExit != 0)
1404 rcExit = errx(2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
1405 #endif
3841406 }
385 psz = argv[i];
386 }
387
388 fd = (int)strtol(psz, &psz, 0);
389 if (!fd || *psz)
390 {
391 fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
392 return 1;
393
394 }
395 if (fd < 0)
396 {
397 fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
398 return 1;
399 }
400 /** @todo deal with stderr */
401 safeCloseFd(fd);
402 continue;
403 }
404
405 /*
406 * Parse a file descriptor argument.
407 */
408
409 /* mode */
410 switch (*psz)
411 {
412 case 'r':
413 psz++;
414 if (*psz == '+')
1407 }
1408 }
1409 else
1410 {
1411 /*
1412 * Open file as a given file descriptor.
1413 */
1414 int fdOpened;
1415 int fOpen;
1416
1417 /* mode */
1418 switch (chOpt)
1419 {
1420 case 'r':
1421 chOpt = *pszArg++;
1422 if (chOpt == '+')
1423 {
1424 fOpen = O_RDWR;
1425 chOpt = *pszArg++;
1426 }
1427 else
1428 fOpen = O_RDONLY;
1429 break;
1430
1431 case 'w':
1432 chOpt = *pszArg++;
1433 if (chOpt == '+')
1434 {
1435 fOpen = O_RDWR | O_CREAT | O_TRUNC;
1436 chOpt = *pszArg++;
1437 }
1438 else
1439 fOpen = O_WRONLY | O_CREAT | O_TRUNC;
1440 aOrders[cOrders].fRemoveOnFailure = 1;
1441 break;
1442
1443 case 'a':
1444 chOpt = *pszArg++;
1445 if (chOpt == '+')
1446 {
1447 fOpen = O_RDWR | O_CREAT | O_APPEND;
1448 chOpt = *pszArg++;
1449 }
1450 else
1451 fOpen = O_WRONLY | O_CREAT | O_APPEND;
1452 break;
1453
1454 case 'i': /* make sure stdin is read-only. */
1455 fOpen = O_RDONLY;
1456 break;
1457
1458 case '+':
1459 rcExit = errx(2, "syntax error: Unexpected '+' in '%s'", argv[iArg]);
1460 continue;
1461
1462 default:
1463 fOpen = O_RDWR | O_CREAT | O_TRUNC;
1464 aOrders[cOrders].fRemoveOnFailure = 1;
1465 break;
1466 }
1467
1468 /* binary / text modifiers */
1469 switch (chOpt)
1470 {
1471 case 'b':
1472 chOpt = *pszArg++;
1473 default:
1474 #ifdef O_BINARY
1475 fOpen |= O_BINARY;
1476 #elif defined(_O_BINARY)
1477 fOpen |= _O_BINARY;
1478 #endif
1479 break;
1480
1481 case 't':
1482 #ifdef O_TEXT
1483 fOpen |= O_TEXT;
1484 #elif defined(_O_TEXT)
1485 fOpen |= _O_TEXT;
1486 #endif
1487 chOpt = *pszArg++;
1488 break;
1489
1490 }
1491
1492 /* convert to file descriptor number */
1493 switch (chOpt)
1494 {
1495 case 'i':
1496 fd = 0;
1497 break;
1498
1499 case 'o':
1500 fd = 1;
1501 break;
1502
1503 case 'e':
1504 fd = 2;
1505 break;
1506
1507 case '0':
1508 if (*pszArg == '\0')
1509 {
1510 fd = 0;
1511 break;
1512 }
1513 case '1':
1514 case '2':
1515 case '3':
1516 case '4':
1517 case '5':
1518 case '6':
1519 case '7':
1520 case '8':
1521 case '9':
1522 pszValue = pszArg - 1;
1523 fd = (int)strtol(pszValue, &pszArg, 0);
1524 if (pszArg == pszValue)
1525 rcExit = errx(2, "error: failed to convert '%s' to a number", argv[iArg]);
1526 else if (fd < 0)
1527 rcExit = errx(2, "error: negative fd %d (%s)", fd, argv[iArg]);
1528 else
1529 break;
1530 continue;
1531
1532 /*
1533 * Invalid argument.
1534 */
1535 default:
1536 rcExit = errx(2, "error: failed to convert '%s' ('%s') to a file descriptor", pszArg, argv[iArg]);
1537 continue;
1538 }
1539
1540 /*
1541 * Check for the filename.
1542 */
1543 if (*pszArg != '\0')
1544 {
1545 if (*pszArg != ':' && *pszArg != '=')
4151546 {
416 fOpen = O_RDWR;
417 psz++;
418 }
419 else
420 fOpen = O_RDONLY;
421 break;
422
423 case 'w':
424 psz++;
425 if (*psz == '+')
426 {
427 psz++;
428 fOpen = O_RDWR | O_CREAT | O_TRUNC;
429 }
430 else
431 fOpen = O_WRONLY | O_CREAT | O_TRUNC;
432 break;
433
434 case 'a':
435 psz++;
436 if (*psz == '+')
437 {
438 psz++;
439 fOpen = O_RDWR | O_CREAT | O_APPEND;
440 }
441 else
442 fOpen = O_WRONLY | O_CREAT | O_APPEND;
443 break;
444
445 case 'i': /* make sure stdin is read-only. */
446 fOpen = O_RDONLY;
447 break;
448
449 case '+':
450 fprintf(pStdErr, "%s: syntax error: Unexpected '+' in '%s'\n", name(argv[0]), argv[i]);
451 return 1;
452
453 default:
454 fOpen = O_RDWR | O_CREAT | O_TRUNC;
455 break;
456 }
457
458 /* binary / text modifiers */
459 switch (*psz)
460 {
461 case 'b':
462 #ifdef O_BINARY
463 fOpen |= O_BINARY;
464 #endif
465 psz++;
466 break;
467
468 case 't':
469 #ifdef O_TEXT
470 fOpen |= O_TEXT;
471 #endif
472 psz++;
473 break;
474
475 default:
476 #ifdef O_BINARY
477 fOpen |= O_BINARY;
478 #endif
479 break;
480
481 }
482
483 /* convert to file descriptor number */
484 switch (*psz)
485 {
486 case 'i':
487 fd = 0;
488 psz++;
489 break;
490
491 case 'o':
492 fd = 1;
493 psz++;
494 break;
495
496 case 'e':
497 fd = 2;
498 psz++;
499 break;
500
501 case '0':
502 if (!psz[1])
503 {
504 fd = 0;
505 psz++;
1547 rcExit = errx(2, "syntax error: characters following the file descriptor: '%s' ('%s')",
1548 pszArg, argv[iArg]);
5061549 break;
5071550 }
508 case '1':
509 case '2':
510 case '3':
511 case '4':
512 case '5':
513 case '6':
514 case '7':
515 case '8':
516 case '9':
517 fd = (int)strtol(psz, &psz, 0);
518 if (!fd)
1551 pszArg++;
1552 }
1553 else if (++iArg < argc)
1554 pszArg = argv[iArg];
1555 else
1556 {
1557 rcExit = errx(2, "syntax error: missing filename argument.");
1558 break;
1559 }
1560
1561 /*
1562 * Open the file. We could've used posix_spawn_file_actions_addopen here,
1563 * but that means complicated error reporting. So, since we need to do
1564 * this for windows anyway, just do it the same way everywhere.
1565 */
1566 fdOpened = kRedirectOpenWithoutConflict(pszArg, fOpen, 0666, cOrders, aOrders,
1567 aOrders[cOrders].fRemoveOnFailure, fd);
1568 if (fdOpened >= 0)
1569 {
1570 aOrders[cOrders].enmOrder = kRedirectOrder_Open;
1571 aOrders[cOrders].fdTarget = fd;
1572 aOrders[cOrders].fdSource = fdOpened;
1573 aOrders[cOrders].fOpen = fOpen;
1574 aOrders[cOrders].pszFilename = pszArg;
1575 cOrders++;
1576
1577 #ifdef USE_POSIX_SPAWN
1578 if (fdOpened != fdSource)
5191579 {
520 fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
521 return 1;
522
1580 rcExit = posix_spawn_file_actions_adddup2(&FileActions, fdOpened, fd);
1581 if (rcExit != 0)
1582 rcExit = err(9, "posix_spawn_file_actions_adddup2(,%d [%s], %d) failed: %s",
1583 fdOpened, fd, pszArg, strerror(rcExit));
5231584 }
524 if (fd < 0)
525 {
526 fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
527 return 1;
528 }
529 break;
530
531 /*
532 * Invalid argument.
533 */
534 default:
535 fprintf(pStdErr, "%s: error: failed to convert '%s' ('%s') to a file descriptor\n", name(argv[0]), psz, argv[i]);
536 return 1;
537 }
538
539 /*
540 * Check for the filename.
541 */
542 if (*psz)
543 {
544 if (*psz != ':' && *psz != '=')
545 {
546 fprintf(pStdErr, "%s: syntax error: characters following the file descriptor: '%s' ('%s')\n", name(argv[0]), psz, argv[i]);
547 return 1;
548 }
549 psz++;
550 }
551 else
552 {
553 i++;
554 if (i >= argc)
555 {
556 fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
557 return 1;
558 }
559 psz = argv[i];
560 }
561
562 /*
563 * Setup the redirection.
564 */
565 if (fd == fileno(pStdErr))
566 {
567 /*
568 * Move stderr to a new location, making it close on exec.
569 * If pStdOut has already teamed up with pStdErr, update it too.
570 */
571 FILE *pNew;
572 fdOpened = dup(fileno(pStdErr));
573 if (fdOpened == -1)
574 {
575 fprintf(pStdErr, "%s: error: failed to dup stderr (%d): %s\n", name(argv[0]), fileno(pStdErr), strerror(errno));
576 return 1;
577 }
578 #ifdef _MSC_VER
579 /** @todo figure out how to make the handle close-on-exec. We'll simply close it for now.
580 * SetHandleInformation + set FNOINHERIT in CRT.
581 */
582 #else
583 if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) == -1)
584 {
585 fprintf(pStdErr, "%s: error: failed to make stderr (%d) close-on-exec: %s\n", name(argv[0]), fdOpened, strerror(errno));
586 return 1;
587 }
588 #endif
589
590 pNew = fdopen(fdOpened, "w");
591 if (!pNew)
592 {
593 fprintf(pStdErr, "%s: error: failed to fdopen the new stderr (%d): %s\n", name(argv[0]), fdOpened, strerror(errno));
594 return 1;
595 }
596 if (pStdOut == pStdErr)
597 pStdOut = pNew;
598 pStdErr = pNew;
599 }
600 else if (fd == 1 && pStdOut != pStdErr)
601 pStdOut = pStdErr;
602
603 /*
604 * Close and open the new file descriptor.
605 */
606 safeCloseFd(fd);
607 #if defined(_MSC_VER)
608 if (!strcmp(psz, "/dev/null"))
609 psz = (char *)"nul";
610 #endif
611 fdOpened = open(psz, fOpen, 0666);
612 if (fdOpened == -1)
613 {
614 fprintf(pStdErr, "%s: error: failed to open '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
615 return 1;
616 }
617 if (fdOpened != fd)
618 {
619 /* move it (dup2 returns 0 on MSC). */
620 if (dup2(fdOpened, fd) == -1)
621 {
622 fprintf(pStdErr, "%s: error: failed to dup '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
623 return 1;
624 }
625 close(fdOpened);
1585 #endif
1586 }
1587 else
1588 rcExit = 9;
6261589 }
6271590 }
6281591 else
6291592 {
630 fprintf(pStdErr, "%s: syntax error: Invalid argument '%s'.\n", name(argv[0]), argv[i]);
631 return usage(pStdErr, name(argv[0]));
1593 errx(2, "syntax error: Invalid argument '%s'.", argv[iArg]);
1594 rcExit = usage(stderr, argv[0]);
6321595 }
6331596 }
1597 if (!pszExecutable)
1598 pszExecutable = argv[iArg];
6341599
6351600 /*
6361601 * Make sure there's something to execute.
6371602 */
638 if (i >= argc)
1603 if (rcExit == 0 && iArg < argc)
6391604 {
640 fprintf(pStdErr, "%s: syntax error: nothing to execute!\n", name(argv[0]));
641 return usage(pStdErr, name(argv[0]));
1605 /*
1606 * Do the spawning in a separate function (main is far to large as it is by now).
1607 */
1608 rcExit = kRedirectDoSpawn(pszExecutable, argc - iArg, &argv[iArg], fWatcomBrainDamage, papszEnv, szCwd, pszSavedCwd,
1609 #ifdef USE_POSIX_SPAWN
1610 cOrders, aOrders, &FileActions, cVerbosity,
1611 #else
1612 cOrders, aOrders, cVerbosity,
1613 #endif
1614 #ifdef KMK
1615 pPidSpawned,
1616 #endif
1617 &fChildExitCode);
6421618 }
643
644 #if defined(_MSC_VER)
645 if (fileno(pStdErr) != 2) /* no close-on-exec flag on windows */
1619 else if (rcExit == 0)
6461620 {
647 fclose(pStdErr);
648 pStdErr = NULL;
1621 errx(2, "syntax error: nothing to execute!");
1622 rcExit = usage(stderr, argv[0]);
6491623 }
650
651 /* MSC is a PITA since it refuses to quote the arguments... */
652 quote_argv(argc - i, &argv[i], fWatcomBrainDamage, 0 /*fFreeOrLeak*/);
653 if (g_cVerbosity > 0)
654 for (j = i; j < argc; j++)
655 fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", j - i, argv[j]);
656 rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
657 if (rc == -1 && pStdErr)
658 {
659 fprintf(pStdErr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
660 rc = 1;
661 }
662 return rc;
663 #else
664 if (g_cVerbosity > 0)
665 for (j = i; j < argc; j++)
666 fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", j - i, argv[j]);
667 execvp(argv[i], &argv[i]);
668 fprintf(pStdErr, "%s: error: _execvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
669 return 1;
670 #endif
1624 /* Help and version sets rcExit to -1. Change it to zero. */
1625 else if (rcExit == -1)
1626 rcExit = 0;
1627
1628 /*
1629 * Cleanup.
1630 */
1631 if (pszSavedCwd)
1632 free(pszSavedCwd);
1633 kRedirectCleanupFdOrders(cOrders, aOrders, rcExit != 0 && !fChildExitCode);
1634 #ifdef USE_POSIX_SPAWN
1635 posix_spawn_file_actions_destroy(&FileActions);
1636 #endif
1637 #ifndef KMK
1638 iEnvVar = cEnvVars;
1639 while (iEnvVar-- > 0)
1640 free(papszEnv[iEnvVar]);
1641 free(papszEnv);
1642 #endif
1643 #ifdef KBUILD_OS_OS2
1644 for (ulLibPath = 0; ulLibPath < K_ELEMENTS(apszSavedLibPaths); ulLibPath++)
1645 if (apszSavedLibPaths[ulLibPath] != NULL)
1646 {
1647 APIRET rc = DosSetExtLIBPATH(apszSavedLibPaths[ulLibPath], ulLibPath);
1648 if (rc != 0)
1649 warnx("DosSetExtLIBPATH('%s',%u) failed with %u when restoring the original values!",
1650 apszSavedLibPaths[ulLibPath], ulLibPath, rc);
1651 free(apszSavedLibPaths[ulLibPath])
1652 }
1653 #endif
1654
1655 return rcExit;
6711656 }
6721657
387387 switch (p->fts_info) {
388388 case FTS_DP:
389389 case FTS_DNR:
390 #ifdef KBUILD_OS_WINDOWS
391 if (p->fts_parent->fts_dirfd != NT_FTS_INVALID_HANDLE_VALUE) {
392 rval = birdUnlinkForcedEx(p->fts_parent->fts_dirfd, p->fts_name);
393 } else {
394 rval = birdUnlinkForced(p->fts_accpath);
395 }
396 #else
390397 rval = rmdir(p->fts_accpath);
398 #endif
391399 if (rval == 0 || (fflag && errno == ENOENT)) {
392400 if (rval == 0 && vflag)
393401 (void)printf("%s\n",
394402 p->fts_path);
403 #if defined(KMK) && defined(KBUILD_OS_WINDOWS)
404 if (rval == 0) {
405 extern int dir_cache_deleted_directory(const char *pszDir);
406 dir_cache_deleted_directory(p->fts_accpath);
407 }
408 #endif
395409 continue;
396410 }
397 operation = "mkdir";
411 operation = "rmdir";
398412 break;
399413
400414 #ifdef FTS_W
423437 if (!rm_overwrite(p->fts_accpath, NULL))
424438 continue;
425439 #ifdef KBUILD_OS_WINDOWS
426 rval = birdUnlinkForcedFast(p->fts_accpath);
440 if (p->fts_parent->fts_dirfd != NT_FTS_INVALID_HANDLE_VALUE) {
441 rval = birdUnlinkForcedFastEx(p->fts_parent->fts_dirfd, p->fts_name);
442 } else {
443 rval = birdUnlinkForcedFast(p->fts_accpath);
444 }
427445 #else
428446 rval = unlink(p->fts_accpath);
429447 #endif
5858 #ifdef _MSC_VER
5959 # include "mscfakes.h"
6060 #endif
61 #if defined(KMK) && defined(KBUILD_OS_WINDOWS)
62 extern int dir_cache_deleted_directory(const char *pszDir);
63 #endif
6164
6265 static int rm_path(char *);
6366 static int usage(FILE *);
133136 if (!ignore_fail_on_not_exist || errno != ENOENT)
134137 continue;
135138 /* (only ignored doesn't exist errors fall thru) */
136 } else if (vflag) {
137 printf("%s\n", *argv);
139 } else {
140 #if defined(KMK) && defined(KBUILD_OS_WINDOWS)
141 dir_cache_deleted_directory(*argv);
142 #endif
143 if (vflag) {
144 printf("%s\n", *argv);
145 }
138146 }
139147 if (pflag)
140148 errors |= rm_path(*argv);
176184 #endif
177185
178186 if (rmdir(path) < 0) {
179 if (ignore_fail_on_non_empty && (errno == ENOTEMPTY || errno == EPERM || errno == EACCES || errno == EINVAL || errno == EEXIST))
187 if ( ignore_fail_on_non_empty
188 && ( errno == ENOTEMPTY || errno == EPERM || errno == EACCES || errno == EINVAL || errno == EEXIST))
180189 break;
181190 if (!ignore_fail_on_not_exist || errno != ENOENT) {
182191 warn("rmdir: %s", path);
183192 return (1);
184193 }
185194 }
195 #if defined(KMK) && defined(KBUILD_OS_WINDOWS)
196 else {
197 dir_cache_deleted_directory(path);
198 }
199 #endif
186200 if (vflag)
187201 printf("%s\n", path);
188202 }
0 /* $Id: kmkbuiltin.c 2843 2016-08-28 15:31:02Z bird $ */
0 /* $Id: kmkbuiltin.c 2912 2016-09-14 13:36:15Z bird $ */
11 /** @file
22 * kMk Builtin command execution.
33 */
204204 rc = kmk_builtin_mkdir(argc, argv, environ);
205205 else if (!strcmp(pszCmd, "mv"))
206206 rc = kmk_builtin_mv(argc, argv, environ);
207 /*else if (!strcmp(pszCmd, "redirect"))
208 rc = kmk_builtin_redirect(argc, argv, environ, pPidSpawned);*/
207 else if (!strcmp(pszCmd, "redirect"))
208 rc = kmk_builtin_redirect(argc, argv, environ, pChild, pPidSpawned);
209209 else if (!strcmp(pszCmd, "rm"))
210210 rc = kmk_builtin_rm(argc, argv, environ);
211211 else if (!strcmp(pszCmd, "rmdir"))
231231 rc = kmk_builtin_cat(argc, argv, environ);
232232 else if (!strcmp(pszCmd, "sleep"))
233233 rc = kmk_builtin_sleep(argc, argv, environ);
234 else if (!strcmp(pszCmd, "dircache"))
235 #ifdef KBUILD_OS_WINDOWS
236 rc = kmk_builtin_dircache(argc, argv, environ);
237 #else
238 rc = 0;
239 #endif
234240 else
235241 {
236242 printf("kmk_builtin: Unknown command '%s'!\n", pszCmd);
0 /* $Id: kmkbuiltin.h 2899 2016-09-09 09:03:57Z bird $ */
0 /* $Id: kmkbuiltin.h 2912 2016-09-14 13:36:15Z bird $ */
11 /** @file
22 * kMk Builtin command handling.
33 */
4444 extern int kmk_builtin_cat(int argc, char **argv, char **envp);
4545 extern int kmk_builtin_chmod(int argc, char **argv, char **envp);
4646 extern int kmk_builtin_cmp(int argc, char **argv, char **envp);
47 extern int kmk_builtin_dircache(int argc, char **argv, char **envp);
4748 extern int kmk_builtin_echo(int argc, char **argv, char **envp);
4849 extern int kmk_builtin_expr(int argc, char **argv, char **envp);
4950 extern int kmk_builtin_install(int argc, char **argv, char **envp);
5253 extern int kmk_builtin_mkdir(int argc, char **argv, char **envp);
5354 extern int kmk_builtin_mv(int argc, char **argv, char **envp);
5455 extern int kmk_builtin_printf(int argc, char **argv, char **envp);
56 extern int kmk_builtin_redirect(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned);
5557 extern int kmk_builtin_rm(int argc, char **argv, char **envp);
5658 extern int kmk_builtin_rmdir(int argc, char **argv, char **envp);
5759 extern int kmk_builtin_sleep(int argc, char **argv, char **envp);
7173
7274 extern char *kmk_builtin_func_printf(char *o, char **argv, const char *funcname);
7375
76 /* common-env-and-cwd-opt.c: */
77 extern int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
78 int cVerbosity, const char *pszValue);
79 extern int kBuiltinOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove);
80 extern int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue);
81
7482 #endif
7583
8888
8989 #ifdef CONFIG_WITH_PRINT_STATS_SWITCH
9090 void print_variable_stats (void);
91 void print_dir_stats (void);
9192 void print_file_stats (void);
9293 #endif
9394
914915
915916
916917 #ifdef WINDOWS32
918 # ifndef KMK
917919 /*
918920 * HANDLE runtime exceptions by avoiding a requestor on the GUI. Capture
919921 * exception and print it to stderr instead.
988990 return (255); /* not reached */
989991 #endif
990992 }
993 # endif /* !KMK */
991994
992995 /*
993996 * On WIN32 systems we don't have the luxury of a /bin directory that
12301233 {
12311234 # ifdef WINDOWS32
12321235 /* Windows: Count the active CPUs. */
1233 int cpus, i;
1234 SYSTEM_INFO si;
1235 GetSystemInfo(&si);
1236 for (i = cpus = 0; i < sizeof(si.dwActiveProcessorMask) * 8; i++)
1236 int cpus;
1237
1238 /* Process groups (W7+). */
1239 typedef DWORD (WINAPI *PFNGETACTIVEPROCESSORCOUNT)(DWORD);
1240 PFNGETACTIVEPROCESSORCOUNT pfnGetActiveProcessorCount;
1241 pfnGetActiveProcessorCount = (PFNGETACTIVEPROCESSORCOUNT)GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
1242 "GetActiveProcessorCount");
1243 if (pfnGetActiveProcessorCount)
1244 cpus = pfnGetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
1245 /* Legacy (<= Vista). */
1246 else
12371247 {
1238 if (si.dwActiveProcessorMask & 1)
1239 cpus++;
1240 si.dwActiveProcessorMask >>= 1;
1248 int i;
1249 SYSTEM_INFO si;
1250 GetSystemInfo(&si);
1251 for (i = cpus = 0; i < sizeof(si.dwActiveProcessorMask) * 8; i++)
1252 {
1253 if (si.dwActiveProcessorMask & 1)
1254 cpus++;
1255 si.dwActiveProcessorMask >>= 1;
1256 }
12411257 }
1242 return cpus ? cpus : 1;
1258 if (!cpus)
1259 cpus = 1;
1260 if (cpus > 64)
1261 cpus = 64; /* (wait for multiple objects limit) */
1262 return cpus;
12431263
12441264 # elif defined(__OS2__)
12451265 /* OS/2: Count the active CPUs. */
13751395 char *windows32_path = NULL;
13761396
13771397 # ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */
1398 # ifndef KMK /* Don't want none of this crap. */
13781399 SetUnhandledExceptionFilter(handle_runtime_exceptions);
1400 # endif
13791401 # endif /* !ELECTRIC_HEAP */
13801402
13811403 /* start off assuming we have no shell */
38573879 /* Make stuff: */
38583880 print_variable_stats ();
38593881 print_file_stats ();
3882 print_dir_stats ();
38603883 # ifdef KMK
38613884 print_kbuild_define_stats ();
38623885 # endif
982982 extern void dir_cache_invalid_all (void);
983983 extern void dir_cache_invalid_missing (void);
984984 extern int dir_cache_volatile_dir (const char *dir);
985 extern int dir_cache_deleted_directory(const char *pszDir);
985986 # endif
986987 #endif
987988
4848 EXTERN_DECL(int process_used_slots, (VOID_DECL));
4949 #ifdef KMK
5050 EXTERN_DECL(int process_kmk_register_submit, (HANDLE hEvent, intptr_t clue, pid_t *pPid));
51 EXTERN_DECL(int process_kmk_register_redirect, (HANDLE hProcess, pid_t *pPid));
5152 #endif
5253
5354 /* support routines */
197197 }
198198
199199 #ifdef KMK
200
200201 /**
201202 * Interface used by kmkbuiltin/kSubmit.c to register stuff going down in a
202203 * worker process.
221222 }
222223 return -1;
223224 }
224 #endif
225
226 /**
227 * Interface used by kmkbuiltin/kRedirect.c to register a spawned process.
228 *
229 * @returns 0 on success, -1 if there are too many sub-processes already.
230 * @param hProcess The process handle.
231 * @param pPid Where to return the pid that job.c expects.
232 */
233 int
234 process_kmk_register_redirect(HANDLE hProcess, pid_t *pPid)
235 {
236 if (proc_index < MAXIMUM_WAIT_OBJECTS) {
237 sub_process *pSubProc = (sub_process *)xcalloc(sizeof(*pSubProc));
238 pSubProc->enmType = kRegular;
239 pSubProc->pid = (intptr_t)hProcess;
240
241 proc_array[proc_index++] = pSubProc;
242 *pPid = (intptr_t)pSubProc;
243 return 0;
244 }
245 return -1;
246 }
247
248 #endif /* KMK */
225249
226250 /*
227251 * Return the number of processes that we are still waiting for.
0 # $Id: Makefile.kmk 2906 2016-09-09 22:15:57Z bird $
0 # $Id: Makefile.kmk 2994 2016-11-01 22:41:41Z bird $
11 ## @file
22 # Sub-makefile for various libraries and stuff.
33 #
44
55 #
6 # Copyright (c) 2006-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
6 # Copyright (c) 2006-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
77 #
88 # This file is part of kBuild.
99 #
5151 nt/ntdir.c \
5252 nt/ntstat.c \
5353 nt/ntunlink.c \
54 nt/fts-nt.c \
5455 nt/kFsCache.c \
5556 kStuff/kHlp/CRT/kHlpCRTString.cpp \
5657 kStuff/kHlp/CRT/kHlpCRTAlloc.cpp
7879 tstNtStat_LIBS = $(LIB_KUTIL)
7980 tstNtStat_NOINST = 1
8081
82 PROGRAMS.win += tstNtFts
83 tstNtFts_TEMPLATE = BIN
84 tstNtFts_SOURCES = nt/tstNtFts.c nt/fts-nt.c
85 tstNtFts_LIBS = $(LIB_KUTIL)
86 tstNtFts_NOINST = 1
87
8188 include $(FILE_KBUILD_SUB_FOOTER)
8289
0 /* $Id: kDep.c 2886 2016-09-06 14:31:46Z bird $ */
0 /* $Id: kDep.c 2955 2016-09-21 19:05:53Z bird $ */
11 /** @file
22 * kDep - Common Dependency Managemnt Code.
33 */
5757
5858 #include "kDep.h"
5959
60 #ifdef KWORKER
61 extern int kwFsPathExists(const char *pszPath);
62 #endif
63
6064
6165 /*******************************************************************************
6266 * Global Variables *
181185 /**
182186 * 'Optimizes' and corrects the dependencies.
183187 */
184 void depOptimize(int fFixCase, int fQuiet)
188 void depOptimize(int fFixCase, int fQuiet, const char *pszIgnoredExt)
185189 {
186190 /*
187191 * Walk the list correct the names and re-insert them.
188192 */
189 PDEP pDepOrg = g_pDeps;
190 PDEP pDep = g_pDeps;
193 size_t cchIgnoredExt = pszIgnoredExt ? strlen(pszIgnoredExt) : 0;
194 PDEP pDepOrg = g_pDeps;
195 PDEP pDep = g_pDeps;
191196 g_pDeps = NULL;
192197 for (; pDep; pDep = pDep->pNext)
193198 {
197202 char szFilename[PATH_MAX + 1];
198203 #endif
199204 char *pszFilename;
200 #ifndef KMK
205 #if !defined(KWORKER) && !defined(KMK)
201206 struct stat s;
202207 #endif
203208
208213 && pDep->szFilename[pDep->cchFilename - 1] == '>')
209214 continue;
210215 pszFilename = pDep->szFilename;
216
217 /*
218 * Skip pszIgnoredExt if given.
219 */
220 if ( pszIgnoredExt
221 && pDep->cchFilename > cchIgnoredExt
222 && memcmp(&pDep->szFilename[pDep->cchFilename - cchIgnoredExt], pszIgnoredExt, cchIgnoredExt) == 0)
223 continue;
211224
212225 #if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS
213226 /*
237250 /*
238251 * Check that the file exists before we start depending on it.
239252 */
240 #ifdef KMK
253 #ifdef KWORKER
254 if (!kwFsPathExists(pszFilename))
255 #elif defined(KMK)
241256 if (!file_exists_p(pszFilename))
242257 #elif K_OS == K_OS_WINDOWS
243258 if (birdStatModTimeOnly(pszFilename, &s.st_mtim, 1 /*fFollowLink*/) != 0)
0 /* $Id: kDep.h 2851 2016-08-31 17:30:52Z bird $ */
0 /* $Id: kDep.h 2955 2016-09-21 19:05:53Z bird $ */
11 /** @file
22 * kDep - Common Dependency Managemnt Code.
33 */
4646
4747
4848 extern PDEP depAdd(const char *pszFilename, size_t cchFilename);
49 extern void depOptimize(int fFixCase, int fQuiet);
49 extern void depOptimize(int fFixCase, int fQuiet, const char *pszIgnoredExt);
5050 extern void depPrint(FILE *pOutput);
5151 extern void depPrintStubs(FILE *pOutput);
5252 extern void depCleanup(void);
0 /* $Id: kHlpAssert.h 70 2015-08-13 09:03:02Z bird $ */
0 /* $Id: kHlpAssert.h 93 2016-09-15 11:53:59Z bird $ */
11 /** @file
22 * kHlpAssert - Assertion Macros.
33 */
220220 #define kHlpAssertRC(rc) kHlpAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
221221 #define kHlpAssertRCReturn(rc, rcRet) kHlpAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
222222 #define kHlpAssertRCReturnVoid(rc) kHlpAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)))
223 #define kHlpAssertFailed() kHlpAssert(0)
224 #define kHlpAssertFailedReturn(rcRet) kHlpAssertReturn(0, (rcRet))
225 #define kHlpAssertFailedReturnVoid() kHlpAssertReturnVoid(0)
226 #define kHlpAssertMsgFailed(msg) kHlpAssertMsg(0, msg)
227 #define kHlpAssertMsgFailedReturn(msg, rcRet) kHlpAssertMsgReturn(0, msg, (rcRet))
228 #define kHlpAssertMsgFailedReturnVoid(msg) kHlpAssertMsgReturnVoid(0, msg))
223 #define kHlpAssertFailed() kHlpAssert(0)
224 #define kHlpAssertFailedStmt(stmt) kHlpAssertStmt(0, stmt)
225 #define kHlpAssertFailedReturn(rcRet) kHlpAssertReturn(0, (rcRet))
226 #define kHlpAssertFailedStmtReturn(stmt, rcRet) kHlpAssertStmtReturn(0, stmt, (rcRet))
227 #define kHlpAssertFailedReturnVoid() kHlpAssertReturnVoid(0)
228 #define kHlpAssertFailedStmtReturnVoid(stmt) kHlpAssertStmtReturnVoid(0, stmt)
229 #define kHlpAssertMsgFailed(msg) kHlpAssertMsg(0, msg)
230 #define kHlpAssertMsgFailedStmt(msg, stmt) kHlpAssertMsgStmt(0, msg, stmt)
231 #define kHlpAssertMsgFailedReturn(msg, rcRet) kHlpAssertMsgReturn(0, msg, (rcRet))
232 #define kHlpAssertMsgFailedStmtReturn(msg, stmt, rcRet) kHlpAssertMsgStmtReturn(0, msg, stmt, (rcRet))
233 #define kHlpAssertMsgFailedReturnVoid(msg) kHlpAssertMsgReturnVoid(0, msg)
234 #define kHlpAssertMsgFailedStmtReturnVoid(msg, stmt) kHlpAssertMsgStmtReturnVoid(0, msg, stmt)
229235
230236 /**
231237 * Helper function that displays the first part of the assertion message.
0 /* $Id: kTypes.h 29 2009-07-01 20:30:29Z bird $ */
0 /* $Id: kTypes.h 95 2016-09-26 07:23:08Z bird $ */
11 /** @file
22 * kTypes - Typedefs And Related Constants And Macros.
33 */
121121 /** @def KSSIZE_MIN
122122 * Memory size min constant.*/
123123 /** @def KSIZE_PRI
124 * Memory size printf format. */
124 * Memory size default printf format (hex). */
125 /** @def KSIZE_PRI_U
126 * Memory size unsigned decimal printf format. */
127 /** @def KSIZE_PRI_I
128 * Memory size signed decimal printf format. */
129 /** @def KSIZE_PRI_X
130 * Memory size hexadecimal printf format. */
125131 /** @def KSSIZE_PRI
126 * Memory size printf format. */
132 * Memory size default printf format (hex). */
133 /** @def KSSIZE_PRI_U
134 * Memory size unsigned decimal printf format. */
135 /** @def KSSIZE_PRI_I
136 * Memory size signed decimal printf format. */
137 /** @def KSSIZE_PRI_X
138 * Memory size hexadecimal printf format. */
127139
128140 /** @typedef KIPTR
129141 * Signed integer type capable of containing a pointer value. */
171183 #define KI64_C(c) (c ## LL)
172184 #define KU64_C(c) (c ## ULL)
173185 #define KI32_C(c) (c)
174 #define KU32_C(c) (c)
186 #define KU32_C(c) (c ## U)
175187 #define KI16_C(c) (c)
176188 #define KU16_C(c) (c)
177189 #define KI8_C(c) (c)
197209 #define KSIZE_C(c) KU32_C(c)
198210 #define KSIZE_MAX KU32_MAX
199211 #define KSIZE_PRI KX32_PRI
212 #define KSIZE_PRI_U KU32_PRI
213 #define KSIZE_PRI_I KI32_PRI
214 #define KSIZE_PRI_X KX32_PRI
200215 #define KIPTR_C(c) KI32_C(c)
201216
202217 typedef KI32 KIPTR;
244259 typedef signed char KI8;
245260 typedef unsigned char KU8;
246261 #define KI32_C(c) (c)
247 #define KU32_C(c) (c)
262 #define KU32_C(c) (c ## U)
248263 #define KI16_C(c) (c)
249264 #define KU16_C(c) (c)
250265 #define KI8_C(c) (c)
265280 #define KSSIZE_MAX KI64_MAX
266281 #define KSSIZE_MIN KI64_MIN
267282 #define KSSIZE_PRI KX64_PRI
283 #define KSSIZE_PRI_U KU64_PRI
284 #define KSSIZE_PRI_I KI64_PRI
285 #define KSSIZE_PRI_X KX64_PRI
268286
269287 typedef KU64 KSIZE;
270288 #define KSIZE_C(c) KU64_C(c)
271289 #define KSIZE_MAX KU64_MAX
290 #define KSIZE_PRI_U KU64_PRI
291 #define KSIZE_PRI_I KI64_PRI
292 #define KSIZE_PRI_X KX64_PRI
272293 #define KSIZE_PRI KX64_PRI
273294
274295 typedef KI64 KIPTR;
0 /* $Id: msc_buffered_printf.c 2910 2016-09-10 00:57:29Z bird $ */
0 /* $Id: msc_buffered_printf.c 2967 2016-09-26 18:14:13Z bird $ */
11 /** @file
22 * printf, vprintf, fprintf, puts, fputs console optimizations for Windows/MSC.
33 */
4545 #undef fputs
4646 #pragma warning(disable: 4273) /* inconsistent dll linkage*/
4747
48 #ifndef KWORKER
49 # define DLL_IMPORT __declspec(dllexport)
50 #else
51 # define DLL_IMPORT
52 #endif
53
4854 extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile);
4955
5056
5561 * @param pszFormat The format string.
5662 * @param ... Format arguments.
5763 */
58 __declspec(dllexport)
64 DLL_IMPORT
5965 int __cdecl printf(const char *pszFormat, ...)
6066 {
6167 int cchRet;
7480 * @param pszFormat The format string.
7581 * @param va Format arguments.
7682 */
77 __declspec(dllexport)
83 DLL_IMPORT
7884 int __cdecl vprintf(const char *pszFormat, va_list va)
7985 {
8086 /*
112118 * @param pszFormat The format string.
113119 * @param va Format arguments.
114120 */
115 __declspec(dllexport)
121 DLL_IMPORT
116122 int __cdecl fprintf(FILE *pFile, const char *pszFormat, ...)
117123 {
118124 va_list va;
158164 * @returns Units written; 0 & errno on failure.
159165 * @param pszString The string to write. (newline is appended)
160166 */
161 __declspec(dllexport)
167 DLL_IMPORT
162168 int __cdecl puts(const char *pszString)
163169 {
164170 size_t cchString = strlen(pszString);
233239 * @param pszString The string to write (no newline added).
234240 * @param pFile The output file.
235241 */
236 __declspec(dllexport)
242 DLL_IMPORT
237243 int __cdecl fputs(const char *pszString, FILE *pFile)
238244 {
239245 size_t cchString = strlen(pszString);
0 /* $Id: fts-nt.c 2992 2016-11-01 22:06:08Z bird $ */
1 /** @file
2 * Source for the NT port of BSD fts.c.
3 *
4 * @copyright 1990, 1993, 1994 The Regents of the University of California. All rights reserved.
5 * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net>
6 * @licenses BSD3
7 *
8 *
9 * Some hints about how the code works.
10 *
11 * The input directories & files are entered into a pseudo root directory and
12 * processed one after another, depth first.
13 *
14 * Directories are completely read into memory first and arranged as linked
15 * list anchored on FTS::fts_cur. fts_read does a pop-like operation on that
16 * list, freeing the nodes after they've been completely processed.
17 * Subdirectories are returned twice by fts_read, the first time when it
18 * decends into it (FTS_D), and the second time as it ascends from it (FTS_DP).
19 *
20 * In parallel to fts_read, there's the fts_children API that fetches the
21 * directory content in a similar manner, but for the consumption of the API
22 * caller rather than FTS itself. The result hangs on FTS::fts_child so it can
23 * be freed when the directory changes or used by fts_read when it is called
24 * upon to enumerate the directory.
25 *
26 *
27 * The NT port of the code does away with the directory changing in favor of
28 * using directory relative opens (present in NT since for ever, just not
29 * exposed thru Win32). A new FTSENT member fts_dirfd has been added to make
30 * this possible for API users too.
31 *
32 * Note! When using Win32 APIs with path input relative to the current
33 * directory, the internal DOS <-> NT path converter will expand it to a
34 * full path and subject it to the 260 char limit.
35 *
36 * The richer NT directory enumeration API allows us to do away with all the
37 * stat() calls, and not have to do link counting and other interesting things
38 * to try speed things up. (You typical stat() implementation on windows is
39 * actually a directory enum call with the name of the file as filter.)
40 */
41
42 /*-
43 * Copyright (c) 1990, 1993, 1994
44 * The Regents of the University of California. All rights reserved.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 *
70 * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
71 */
72
73 #if 0
74 #if defined(LIBC_SCCS) && !defined(lint)
75 static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
76 #endif /* LIBC_SCCS and not lint */
77 #endif
78
79 #include <errno.h>
80 #include "fts-nt.h"
81 #include <stdlib.h>
82 #include <string.h>
83 #include <assert.h>
84 #include "nthlp.h"
85 #include "ntdir.h"
86
87 static FTSENT *fts_alloc(FTS *, char *, size_t);
88 static FTSENT *fts_build(FTS *, int);
89 static void fts_lfree(FTSENT *);
90 static void fts_load(FTS *, FTSENT *);
91 static size_t fts_maxarglen(char * const *);
92 static void fts_padjust(FTS *, FTSENT *);
93 static int fts_palloc(FTS *, size_t);
94 static FTSENT *fts_sort(FTS *, FTSENT *, size_t);
95 static int fts_stat(FTS *, FTSENT *, int, HANDLE);
96 static int fts_process_stats(FTSENT *, BirdStat_T const *);
97
98 #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
99
100 #define CLR(opt) (sp->fts_options &= ~(opt))
101 #define ISSET(opt) (sp->fts_options & (opt))
102 #define SET(opt) (sp->fts_options |= (opt))
103
104 /* fts_build flags */
105 #define BCHILD 1 /* fts_children */
106 #define BNAMES 2 /* fts_children, names only */
107 #define BREAD 3 /* fts_read */
108
109 /* NT needs these: */
110 #define MAXPATHLEN 260
111 #define MAX(a, b) ( (a) >= (b) ? (a) : (b) )
112
113 #define AT_SYMLINK_NOFOLLOW 1
114 #define fstatat(hDir, pszPath, pStat, fFlags) birdStatAt((hDir), (pszPath), (pStat), (fFlags) != AT_SYMLINK_NOFOLLOW)
115 #define FTS_NT_DUMMY_SYMFD_VALUE ((HANDLE)~(intptr_t)(2)) /* current process */
116
117 /*
118 * Internal representation of an FTS, including extra implementation
119 * details. The FTS returned from fts_open points to this structure's
120 * ftsp_fts member (and can be cast to an _fts_private as required)
121 */
122 struct _fts_private {
123 FTS ftsp_fts;
124 };
125
126
127 FTS * FTSCALL
128 nt_fts_open(char * const *argv, int options,
129 int (*compar)(const FTSENT * const *, const FTSENT * const *))
130 {
131 struct _fts_private *priv;
132 FTS *sp;
133 FTSENT *p, *root;
134 FTSENT *parent, *tmp;
135 size_t len, nitems;
136
137 /* Options check. */
138 if (options & ~FTS_OPTIONMASK) {
139 errno = EINVAL;
140 return (NULL);
141 }
142
143 /* fts_open() requires at least one path */
144 if (*argv == NULL) {
145 errno = EINVAL;
146 return (NULL);
147 }
148
149 /* Allocate/initialize the stream. */
150 if ((priv = calloc(1, sizeof(*priv))) == NULL)
151 return (NULL);
152 sp = &priv->ftsp_fts;
153 sp->fts_compar = compar;
154 sp->fts_options = options;
155 SET(FTS_NOCHDIR); /* NT: FTS_NOCHDIR is always on (for external consumes) */
156
157 /* Shush, GCC. */
158 tmp = NULL;
159
160 /*
161 * Start out with 1K of path space, and enough, in any case,
162 * to hold the user's paths.
163 */
164 if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
165 goto mem1;
166
167 /* Allocate/initialize root's parent. */
168 if ((parent = fts_alloc(sp, "", 0)) == NULL)
169 goto mem2;
170 parent->fts_level = FTS_ROOTPARENTLEVEL;
171
172 /* Allocate/initialize root(s). */
173 for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
174 /* NT: We need to do some small input transformations to make this and
175 the API user code happy. 1. Lone drive letters get a dot
176 appended so it won't matter if a slash is appended afterwards.
177 2. DOS slashes are converted to UNIX ones. */
178 char *slash;
179 len = strlen(*argv);
180 if (len == 2 && argv[0][1] == ':') {
181 char tmp[4];
182 tmp[0] = argv[0][0];
183 tmp[1] = ':';
184 tmp[2] = '.';
185 tmp[3] = '\0';
186 p = fts_alloc(sp, tmp, 3);
187 } else {
188 p = fts_alloc(sp, *argv, len);
189 }
190 #if 1 /* bird */
191 if (p != NULL) { /* likely */ } else { goto mem3; }
192 #endif
193 slash = strchr(p->fts_name, '\\');
194 while (slash != NULL) {
195 *slash++ = '/';
196 slash = strchr(p->fts_name, '\\');
197 }
198 p->fts_level = FTS_ROOTLEVEL;
199 p->fts_parent = parent;
200 p->fts_accpath = p->fts_name;
201 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), INVALID_HANDLE_VALUE);
202
203 /* Command-line "." and ".." are real directories. */
204 if (p->fts_info == FTS_DOT)
205 p->fts_info = FTS_D;
206
207 /*
208 * If comparison routine supplied, traverse in sorted
209 * order; otherwise traverse in the order specified.
210 */
211 if (compar) {
212 p->fts_link = root;
213 root = p;
214 } else {
215 p->fts_link = NULL;
216 if (root == NULL)
217 tmp = root = p;
218 else {
219 tmp->fts_link = p;
220 tmp = p;
221 }
222 }
223 }
224 if (compar && nitems > 1)
225 root = fts_sort(sp, root, nitems);
226
227 /*
228 * Allocate a dummy pointer and make fts_read think that we've just
229 * finished the node before the root(s); set p->fts_info to FTS_INIT
230 * so that everything about the "current" node is ignored.
231 */
232 if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
233 goto mem3;
234 sp->fts_cur->fts_link = root;
235 sp->fts_cur->fts_info = FTS_INIT;
236
237 return (sp);
238
239 mem3: fts_lfree(root);
240 free(parent);
241 mem2: free(sp->fts_path);
242 mem1: free(sp);
243 return (NULL);
244 }
245
246
247 static void
248 fts_load(FTS *sp, FTSENT *p)
249 {
250 size_t len;
251 char *cp;
252
253 /*
254 * Load the stream structure for the next traversal. Since we don't
255 * actually enter the directory until after the preorder visit, set
256 * the fts_accpath field specially so the chdir gets done to the right
257 * place and the user can access the first node. From fts_open it's
258 * known that the path will fit.
259 */
260 len = p->fts_pathlen = p->fts_namelen;
261 memmove(sp->fts_path, p->fts_name, len + 1);
262 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
263 len = strlen(++cp);
264 memmove(p->fts_name, cp, len + 1);
265 p->fts_namelen = len;
266 }
267 p->fts_accpath = p->fts_path = sp->fts_path;
268 sp->fts_dev = p->fts_dev;
269 }
270
271 int FTSCALL
272 nt_fts_close(FTS *sp)
273 {
274 FTSENT *freep, *p;
275 /*int saved_errno;*/
276
277 /*
278 * This still works if we haven't read anything -- the dummy structure
279 * points to the root list, so we step through to the end of the root
280 * list which has a valid parent pointer.
281 */
282 if (sp->fts_cur) {
283 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
284 freep = p;
285 p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
286 free(freep);
287 }
288 free(p);
289 }
290
291 /* Free up child linked list, sort array, path buffer. */
292 if (sp->fts_child)
293 fts_lfree(sp->fts_child);
294 if (sp->fts_array)
295 free(sp->fts_array);
296 free(sp->fts_path);
297
298 /* Free up the stream pointer. */
299 free(sp);
300 return (0);
301 }
302
303 /*
304 * Special case of "/" at the end of the path so that slashes aren't
305 * appended which would cause paths to be written as "....//foo".
306 */
307 #define NAPPEND(p) \
308 (p->fts_path[p->fts_pathlen - 1] == '/' \
309 ? p->fts_pathlen - 1 : p->fts_pathlen)
310
311 static void
312 fts_free_entry(FTSENT *tmp)
313 {
314 if (tmp != NULL) {
315 if (tmp->fts_dirfd != INVALID_HANDLE_VALUE) {
316 birdCloseFile(tmp->fts_dirfd);
317 tmp->fts_dirfd = INVALID_HANDLE_VALUE;
318 }
319 free(tmp);
320 }
321 }
322
323 FTSENT * FTSCALL
324 nt_fts_read(FTS *sp)
325 {
326 FTSENT *p, *tmp;
327 int instr;
328 char *t;
329
330 /* If finished or unrecoverable error, return NULL. */
331 if (sp->fts_cur == NULL || ISSET(FTS_STOP))
332 return (NULL);
333
334 /* Set current node pointer. */
335 p = sp->fts_cur;
336
337 /* Save and zero out user instructions. */
338 instr = p->fts_instr;
339 p->fts_instr = FTS_NOINSTR;
340
341 /* Any type of file may be re-visited; re-stat and re-turn. */
342 if (instr == FTS_AGAIN) {
343 p->fts_info = fts_stat(sp, p, 0, INVALID_HANDLE_VALUE);
344 return (p);
345 }
346
347 /*
348 * Following a symlink -- SLNONE test allows application to see
349 * SLNONE and recover. If indirecting through a symlink, have
350 * keep a pointer to current location. If unable to get that
351 * pointer, follow fails.
352 *
353 * NT: Since we don't change directory, we just set fts_symfd to a
354 * placeholder value handle value here in case a API client
355 * checks it. Ditto FTS_SYMFOLLOW.
356 */
357 if (instr == FTS_FOLLOW &&
358 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
359 p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE);
360 if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) {
361 p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;
362 p->fts_flags |= FTS_SYMFOLLOW;
363 }
364 return (p);
365 }
366
367 /* Directory in pre-order. */
368 if (p->fts_info == FTS_D) {
369 /* If skipped or crossed mount point, do post-order visit. */
370 if (instr == FTS_SKIP ||
371 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
372 if (p->fts_flags & FTS_SYMFOLLOW) {
373 p->fts_symfd = INVALID_HANDLE_VALUE;
374 }
375 if (sp->fts_child) {
376 fts_lfree(sp->fts_child);
377 sp->fts_child = NULL;
378 }
379 p->fts_info = FTS_DP;
380 return (p);
381 }
382
383 /* Rebuild if only read the names and now traversing. */
384 if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
385 CLR(FTS_NAMEONLY);
386 fts_lfree(sp->fts_child);
387 sp->fts_child = NULL;
388 }
389
390 /*
391 * Cd to the subdirectory.
392 *
393 * If have already read and now fail to chdir, whack the list
394 * to make the names come out right, and set the parent errno
395 * so the application will eventually get an error condition.
396 * Set the FTS_DONTCHDIR flag so that when we logically change
397 * directories back to the parent we don't do a chdir.
398 *
399 * If haven't read do so. If the read fails, fts_build sets
400 * FTS_STOP or the fts_info field of the node.
401 */
402 if (sp->fts_child != NULL) {
403 /* nothing to do */
404 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
405 if (ISSET(FTS_STOP))
406 return (NULL);
407 return (p);
408 }
409 p = sp->fts_child;
410 sp->fts_child = NULL;
411 goto name;
412 }
413
414 /* Move to the next node on this level. */
415 next: tmp = p;
416 if ((p = p->fts_link) != NULL) {
417 /*
418 * If reached the top, return to the original directory (or
419 * the root of the tree), and load the paths for the next root.
420 */
421 if (p->fts_level == FTS_ROOTLEVEL) {
422 fts_free_entry(tmp);
423 fts_load(sp, p);
424 return (sp->fts_cur = p);
425 }
426
427 /*
428 * User may have called fts_set on the node. If skipped,
429 * ignore. If followed, get a file descriptor so we can
430 * get back if necessary.
431 */
432 if (p->fts_instr == FTS_SKIP) {
433 fts_free_entry(tmp);
434 goto next;
435 }
436 if (p->fts_instr == FTS_FOLLOW) {
437 p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE);
438 /* NT: See above regarding fts_symfd. */
439 if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) {
440 p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;
441 p->fts_flags |= FTS_SYMFOLLOW;
442 }
443 p->fts_instr = FTS_NOINSTR;
444 }
445
446 fts_free_entry(tmp);
447
448 name: t = sp->fts_path + NAPPEND(p->fts_parent);
449 *t++ = '/';
450 memmove(t, p->fts_name, p->fts_namelen + 1);
451 return (sp->fts_cur = p);
452 }
453
454 /* Move up to the parent node. */
455 p = tmp->fts_parent;
456
457 if (p->fts_level == FTS_ROOTPARENTLEVEL) {
458 /*
459 * Done; free everything up and set errno to 0 so the user
460 * can distinguish between error and EOF.
461 */
462 fts_free_entry(tmp);
463 fts_free_entry(p);
464 errno = 0;
465 return (sp->fts_cur = NULL);
466 }
467
468 /* NUL terminate the pathname. */
469 sp->fts_path[p->fts_pathlen] = '\0';
470
471 /*
472 * Return to the parent directory. If at a root node or came through
473 * a symlink, go back through the file descriptor. Otherwise, cd up
474 * one directory.
475 *
476 * NT: We're doing no fchdir, but we need to close the directory handle
477 * and clear fts_symfd now.
478 */
479 if (p->fts_flags & FTS_SYMFOLLOW) {
480 p->fts_symfd = INVALID_HANDLE_VALUE;
481 }
482 if (p->fts_dirfd != INVALID_HANDLE_VALUE) {
483 birdCloseFile(p->fts_dirfd);
484 p->fts_dirfd = INVALID_HANDLE_VALUE;
485 }
486 fts_free_entry(tmp);
487 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
488 return (sp->fts_cur = p);
489 }
490
491 /*
492 * Fts_set takes the stream as an argument although it's not used in this
493 * implementation; it would be necessary if anyone wanted to add global
494 * semantics to fts using fts_set. An error return is allowed for similar
495 * reasons.
496 */
497 /* ARGSUSED */
498 int FTSCALL
499 nt_fts_set(FTS *sp, FTSENT *p, int instr)
500 {
501 if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
502 instr != FTS_NOINSTR && instr != FTS_SKIP) {
503 errno = EINVAL;
504 return (1);
505 }
506 p->fts_instr = instr;
507 return (0);
508 }
509
510 FTSENT * FTSCALL
511 nt_fts_children(FTS *sp, int instr)
512 {
513 FTSENT *p;
514
515 if (instr != 0 && instr != FTS_NAMEONLY) {
516 errno = EINVAL;
517 return (NULL);
518 }
519
520 /* Set current node pointer. */
521 p = sp->fts_cur;
522
523 /*
524 * Errno set to 0 so user can distinguish empty directory from
525 * an error.
526 */
527 errno = 0;
528
529 /* Fatal errors stop here. */
530 if (ISSET(FTS_STOP))
531 return (NULL);
532
533 /* Return logical hierarchy of user's arguments. */
534 if (p->fts_info == FTS_INIT)
535 return (p->fts_link);
536
537 /*
538 * If not a directory being visited in pre-order, stop here. Could
539 * allow FTS_DNR, assuming the user has fixed the problem, but the
540 * same effect is available with FTS_AGAIN.
541 */
542 if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
543 return (NULL);
544
545 /* Free up any previous child list. */
546 if (sp->fts_child != NULL) {
547 fts_lfree(sp->fts_child);
548 sp->fts_child = NULL; /* (bird - double free for _open(".") failure in original) */
549 }
550
551 /* NT: Some BSD utility sets FTS_NAMEONLY? We don't really need this
552 optimization, but since it only hurts that utility, it can stay. */
553 if (instr == FTS_NAMEONLY) {
554 assert(0); /* don't specify FTS_NAMEONLY on NT. */
555 SET(FTS_NAMEONLY);
556 instr = BNAMES;
557 } else
558 instr = BCHILD;
559
560 return (sp->fts_child = fts_build(sp, instr));
561 }
562
563 #ifndef fts_get_clientptr
564 #error "fts_get_clientptr not defined"
565 #endif
566
567 void *
568 (FTSCALL fts_get_clientptr)(FTS *sp)
569 {
570
571 return (fts_get_clientptr(sp));
572 }
573
574 #ifndef fts_get_stream
575 #error "fts_get_stream not defined"
576 #endif
577
578 FTS *
579 (FTSCALL fts_get_stream)(FTSENT *p)
580 {
581 return (fts_get_stream(p));
582 }
583
584 void FTSCALL
585 nt_fts_set_clientptr(FTS *sp, void *clientptr)
586 {
587
588 sp->fts_clientptr = clientptr;
589 }
590
591 /*
592 * This is the tricky part -- do not casually change *anything* in here. The
593 * idea is to build the linked list of entries that are used by fts_children
594 * and fts_read. There are lots of special cases.
595 *
596 * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
597 * set and it's a physical walk (so that symbolic links can't be directories),
598 * we can do things quickly. First, if it's a 4.4BSD file system, the type
599 * of the file is in the directory entry. Otherwise, we assume that the number
600 * of subdirectories in a node is equal to the number of links to the parent.
601 * The former skips all stat calls. The latter skips stat calls in any leaf
602 * directories and for any files after the subdirectories in the directory have
603 * been found, cutting the stat calls by about 2/3.
604 *
605 * NT: We do not do any link counting or stat avoiding, which invalidates the
606 * above warnings. This function is very simple for us.
607 */
608 static FTSENT *
609 fts_build(FTS *sp, int type)
610 {
611 BirdDirEntry_T *dp;
612 FTSENT *p, *head;
613 FTSENT *cur, *tail;
614 DIR *dirp;
615 void *oldaddr;
616 char *cp;
617 int saved_errno, doadjust;
618 long level;
619 size_t dnamlen, len, maxlen, nitems;
620 unsigned fDirOpenFlags;
621
622 /* Set current node pointer. */
623 cur = sp->fts_cur;
624
625 /*
626 * Open the directory for reading. If this fails, we're done.
627 * If being called from fts_read, set the fts_info field.
628 *
629 * NT: We do a two stage open so we can keep the directory handle around
630 * after we've enumerated the directory. The dir handle is used by
631 * us here and by the API users to more efficiently and safely open
632 * members of the directory.
633 */
634 fDirOpenFlags = BIRDDIR_F_EXTRA_INFO | BIRDDIR_F_KEEP_HANDLE;
635 if (cur->fts_dirfd == INVALID_HANDLE_VALUE) {
636 if (cur->fts_parent->fts_dirfd != INVALID_HANDLE_VALUE) {
637 /* (This works fine for symlinks too, since we follow them.) */
638 cur->fts_dirfd = birdOpenFileEx(cur->fts_parent->fts_dirfd,
639 cur->fts_name,
640 FILE_READ_DATA | SYNCHRONIZE,
641 FILE_ATTRIBUTE_NORMAL,
642 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
643 FILE_OPEN,
644 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
645 OBJ_CASE_INSENSITIVE);
646 } else {
647 cur->fts_dirfd = birdOpenFile(cur->fts_accpath,
648 FILE_READ_DATA | SYNCHRONIZE,
649 FILE_ATTRIBUTE_NORMAL,
650 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
651 FILE_OPEN,
652 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
653 OBJ_CASE_INSENSITIVE);
654 }
655 } else {
656 fDirOpenFlags |= BIRDDIR_F_RESTART_SCAN;
657 }
658 dirp = birdDirOpenFromHandle(cur->fts_dirfd, NULL, fDirOpenFlags);
659 if (dirp == NULL) {
660 if (type == BREAD) {
661 cur->fts_info = FTS_DNR;
662 cur->fts_errno = errno;
663 }
664 return (NULL);
665 }
666
667 /*
668 * Figure out the max file name length that can be stored in the
669 * current path -- the inner loop allocates more path as necessary.
670 * We really wouldn't have to do the maxlen calculations here, we
671 * could do them in fts_read before returning the path, but it's a
672 * lot easier here since the length is part of the dirent structure.
673 *
674 * If not changing directories set a pointer so that can just append
675 * each new name into the path.
676 */
677 len = NAPPEND(cur);
678 cp = sp->fts_path + len;
679 *cp++ = '/';
680 len++;
681 maxlen = sp->fts_pathlen - len;
682
683 level = cur->fts_level + 1;
684
685 /* Read the directory, attaching each entry to the `link' pointer. */
686 doadjust = 0;
687 for (head = tail = NULL, nitems = 0; dirp && (dp = birdDirRead(dirp));) {
688 dnamlen = dp->d_namlen;
689 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
690 continue;
691
692 if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL)
693 goto mem1;
694 if (dnamlen >= maxlen) { /* include space for NUL */
695 oldaddr = sp->fts_path;
696 if (fts_palloc(sp, dnamlen + len + 1)) {
697 /*
698 * No more memory for path or structures. Save
699 * errno, free up the current structure and the
700 * structures already allocated.
701 */
702 mem1: saved_errno = errno;
703 if (p)
704 free(p);
705 fts_lfree(head);
706 birdDirClose(dirp);
707 birdCloseFile(cur->fts_dirfd);
708 cur->fts_dirfd = INVALID_HANDLE_VALUE;
709 cur->fts_info = FTS_ERR;
710 SET(FTS_STOP);
711 errno = saved_errno;
712 return (NULL);
713 }
714 /* Did realloc() change the pointer? */
715 if (oldaddr != sp->fts_path) {
716 doadjust = 1;
717 if (1 /*ISSET(FTS_NOCHDIR)*/)
718 cp = sp->fts_path + len;
719 }
720 maxlen = sp->fts_pathlen - len;
721 }
722
723 p->fts_level = level;
724 p->fts_parent = sp->fts_cur;
725 p->fts_pathlen = len + dnamlen;
726 p->fts_accpath = p->fts_path;
727 p->fts_stat = dp->d_stat;
728 p->fts_info = fts_process_stats(p, &dp->d_stat);
729
730 /* We walk in directory order so "ls -f" doesn't get upset. */
731 p->fts_link = NULL;
732 if (head == NULL)
733 head = tail = p;
734 else {
735 tail->fts_link = p;
736 tail = p;
737 }
738 ++nitems;
739 }
740
741 birdDirClose(dirp);
742
743 /*
744 * If realloc() changed the address of the path, adjust the
745 * addresses for the rest of the tree and the dir list.
746 */
747 if (doadjust)
748 fts_padjust(sp, head);
749
750 /*
751 * Reset the path back to original state.
752 */
753 sp->fts_path[cur->fts_pathlen] = '\0';
754
755 /* If didn't find anything, return NULL. */
756 if (!nitems) {
757 if (type == BREAD)
758 cur->fts_info = FTS_DP;
759 return (NULL);
760 }
761
762 /* Sort the entries. */
763 if (sp->fts_compar && nitems > 1)
764 head = fts_sort(sp, head, nitems);
765 return (head);
766 }
767
768
769 /**
770 * @note Only used on NT with input arguments, FTS_AGAIN, and links that needs
771 * following. On link information is generally retrieved during directory
772 * enumeration on NT, in line with it's DOS/OS2/FAT API heritage.
773 */
774 static int
775 fts_stat(FTS *sp, FTSENT *p, int follow, HANDLE dfd)
776 {
777 int saved_errno;
778 const char *path;
779
780 if (dfd == INVALID_HANDLE_VALUE) {
781 path = p->fts_accpath;
782 } else {
783 path = p->fts_name;
784 }
785
786 /*
787 * If doing a logical walk, or application requested FTS_FOLLOW, do
788 * a stat(2). If that fails, check for a non-existent symlink. If
789 * fail, set the errno from the stat call.
790 */
791 if (ISSET(FTS_LOGICAL) || follow) {
792 if (fstatat(dfd, path, &p->fts_stat, 0)) {
793 saved_errno = errno;
794 if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) {
795 p->fts_errno = saved_errno;
796 goto err;
797 }
798 errno = 0;
799 if (S_ISLNK(p->fts_stat.st_mode))
800 return (FTS_SLNONE);
801 }
802 } else if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) {
803 p->fts_errno = errno;
804 err: memset(&p->fts_stat, 0, sizeof(struct stat));
805 return (FTS_NS);
806 }
807 return fts_process_stats(p, &p->fts_stat);
808 }
809
810 /* Shared between fts_stat and fts_build. */
811 static int
812 fts_process_stats(FTSENT *p, BirdStat_T const *sbp)
813 {
814 if (S_ISDIR(sbp->st_mode)) {
815 FTSENT *t;
816 fts_dev_t dev;
817 fts_ino_t ino;
818
819 /*
820 * Set the device/inode. Used to find cycles and check for
821 * crossing mount points. Also remember the link count, used
822 * in fts_build to limit the number of stat calls. It is
823 * understood that these fields are only referenced if fts_info
824 * is set to FTS_D.
825 */
826 dev = p->fts_dev = sbp->st_dev;
827 ino = p->fts_ino = sbp->st_ino;
828 p->fts_nlink = sbp->st_nlink;
829
830 if (ISDOT(p->fts_name))
831 return (FTS_DOT);
832
833 /*
834 * Cycle detection is done by brute force when the directory
835 * is first encountered. If the tree gets deep enough or the
836 * number of symbolic links to directories is high enough,
837 * something faster might be worthwhile.
838 */
839 for (t = p->fts_parent;
840 t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
841 if (ino == t->fts_ino && dev == t->fts_dev) {
842 p->fts_cycle = t;
843 return (FTS_DC);
844 }
845 return (FTS_D);
846 }
847 if (S_ISLNK(sbp->st_mode))
848 return (FTS_SL);
849 if (S_ISREG(sbp->st_mode))
850 return (FTS_F);
851 return (FTS_DEFAULT);
852 }
853
854 /*
855 * The comparison function takes pointers to pointers to FTSENT structures.
856 * Qsort wants a comparison function that takes pointers to void.
857 * (Both with appropriate levels of const-poisoning, of course!)
858 * Use a trampoline function to deal with the difference.
859 */
860 static int
861 fts_compar(const void *a, const void *b)
862 {
863 FTS *parent;
864
865 parent = (*(const FTSENT * const *)a)->fts_fts;
866 return (*parent->fts_compar)(a, b);
867 }
868
869 static FTSENT *
870 fts_sort(FTS *sp, FTSENT *head, size_t nitems)
871 {
872 FTSENT **ap, *p;
873
874 /*
875 * Construct an array of pointers to the structures and call qsort(3).
876 * Reassemble the array in the order returned by qsort. If unable to
877 * sort for memory reasons, return the directory entries in their
878 * current order. Allocate enough space for the current needs plus
879 * 40 so don't realloc one entry at a time.
880 */
881 if (nitems > sp->fts_nitems) {
882 void *ptr;
883 sp->fts_nitems = nitems + 40;
884 ptr = realloc(sp->fts_array, sp->fts_nitems * sizeof(FTSENT *));
885 if (ptr != NULL) {
886 sp->fts_array = ptr;
887 } else {
888 free(sp->fts_array);
889 sp->fts_array = NULL;
890 sp->fts_nitems = 0;
891 return (head);
892 }
893 }
894 for (ap = sp->fts_array, p = head; p; p = p->fts_link)
895 *ap++ = p;
896 qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
897 for (head = *(ap = sp->fts_array); --nitems; ++ap)
898 ap[0]->fts_link = ap[1];
899 ap[0]->fts_link = NULL;
900 return (head);
901 }
902
903 static FTSENT *
904 fts_alloc(FTS *sp, char *name, size_t namelen)
905 {
906 FTSENT *p;
907 size_t len;
908
909 struct ftsent_withstat {
910 FTSENT ent;
911 struct stat statbuf;
912 };
913
914 /*
915 * The file name is a variable length array. Allocate the FTSENT
916 * structure and the file name.
917 */
918 len = sizeof(FTSENT) + namelen + 1;
919 if ((p = malloc(len)) == NULL)
920 return (NULL);
921
922 p->fts_name = (char *)(p + 1);
923 p->fts_statp = &p->fts_stat;
924
925 /* Copy the name and guarantee NUL termination. */
926 memcpy(p->fts_name, name, namelen);
927 p->fts_name[namelen] = '\0';
928 p->fts_namelen = namelen;
929 p->fts_path = sp->fts_path;
930 p->fts_errno = 0;
931 p->fts_flags = 0;
932 p->fts_instr = FTS_NOINSTR;
933 p->fts_number = 0;
934 p->fts_pointer = NULL;
935 p->fts_fts = sp;
936 p->fts_symfd = INVALID_HANDLE_VALUE;
937 p->fts_dirfd = INVALID_HANDLE_VALUE;
938 return (p);
939 }
940
941 static void
942 fts_lfree(FTSENT *head)
943 {
944 FTSENT *p;
945
946 /* Free a linked list of structures. */
947 while ((p = head)) {
948 head = head->fts_link;
949 assert(p->fts_dirfd == INVALID_HANDLE_VALUE);
950 free(p);
951 }
952 }
953
954 /*
955 * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
956 * Most systems will allow creation of paths much longer than MAXPATHLEN, even
957 * though the kernel won't resolve them. Add the size (not just what's needed)
958 * plus 256 bytes so don't realloc the path 2 bytes at a time.
959 */
960 static int
961 fts_palloc(FTS *sp, size_t more)
962 {
963 void *ptr;
964
965 sp->fts_pathlen += more + 256;
966 ptr = realloc(sp->fts_path, sp->fts_pathlen);
967 if (ptr) {
968 /*likely */
969 } else {
970 free(sp->fts_path);
971 }
972 sp->fts_path = ptr;
973 return (ptr == NULL);
974 }
975
976 /*
977 * When the path is realloc'd, have to fix all of the pointers in structures
978 * already returned.
979 */
980 static void
981 fts_padjust(FTS *sp, FTSENT *head)
982 {
983 FTSENT *p;
984 char *addr = sp->fts_path;
985
986 #define ADJUST(p) do { \
987 if ((p)->fts_accpath != (p)->fts_name) { \
988 (p)->fts_accpath = \
989 (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
990 } \
991 (p)->fts_path = addr; \
992 } while (0)
993 /* Adjust the current set of children. */
994 for (p = sp->fts_child; p; p = p->fts_link)
995 ADJUST(p);
996
997 /* Adjust the rest of the tree, including the current level. */
998 for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
999 ADJUST(p);
1000 p = p->fts_link ? p->fts_link : p->fts_parent;
1001 }
1002 }
1003
1004 static size_t
1005 fts_maxarglen(char * const *argv)
1006 {
1007 size_t len, max;
1008
1009 for (max = 0; *argv; ++argv)
1010 if ((len = strlen(*argv)) > max)
1011 max = len;
1012 return (max + 1);
1013 }
1014
0 /* $Id: fts-nt.h 2997 2016-11-01 23:28:02Z bird $ */
1 /** @file
2 * Header for the NT port of BSD fts.h.
3 *
4 * @copyright Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved.
5 * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net>
6 * @licenses BSD3
7 */
8
9 /*
10 * Copyright (c) 1989, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)fts.h 8.3 (Berkeley) 8/14/94
38 * $FreeBSD$
39 *
40 */
41
42 #ifndef INCLUDED_FTS_NT_H
43 #define INCLUDED_FTS_NT_H
44
45 #include <sys/types.h>
46 #include <stdint.h>
47 #include "ntstat.h" /* ensure correct stat structure */
48
49 typedef uint64_t fts_dev_t;
50 typedef uint64_t fts_ino_t;
51 typedef uint32_t fts_nlink_t;
52 #ifdef _WINNT_
53 typedef HANDLE fts_fd_t;
54 # define NT_FTS_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE
55 #else
56 typedef void * fts_fd_t;
57 # define NT_FTS_INVALID_HANDLE_VALUE ((void *)~(uintptr_t)0)
58 #endif
59 #define FTSCALL __cdecl
60
61 typedef struct {
62 struct _ftsent *fts_cur; /* current node */
63 struct _ftsent *fts_child; /* linked list of children */
64 struct _ftsent **fts_array; /* sort array */
65 fts_dev_t fts_dev; /* starting device # */
66 char *fts_path; /* path for this descent */
67 size_t fts_pathlen; /* sizeof(path) */
68 size_t fts_nitems; /* elements in the sort array */
69 int (FTSCALL *fts_compar) /* compare function */
70 (const struct _ftsent * const *, const struct _ftsent * const *);
71
72 #define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
73 #define FTS_LOGICAL 0x002 /* logical walk */
74 #define FTS_NOCHDIR 0x004 /* don't change directories */
75 #define FTS_NOSTAT 0x008 /* don't get stat info */
76 #define FTS_PHYSICAL 0x010 /* physical walk */
77 #define FTS_SEEDOT 0x020 /* return dot and dot-dot */
78 #define FTS_XDEV 0x040 /* don't cross devices */
79 #if 0 /* No whiteout on NT. */
80 #define FTS_WHITEOUT 0x080 /* return whiteout information */
81 #endif
82 #define FTS_OPTIONMASK 0x0ff /* valid user option mask */
83
84 #define FTS_NAMEONLY 0x100 /* (private) child names only */
85 #define FTS_STOP 0x200 /* (private) unrecoverable error */
86 int fts_options; /* fts_open options, global flags */
87 void *fts_clientptr; /* thunk for sort function */
88 } FTS;
89
90 typedef struct _ftsent {
91 struct _ftsent *fts_cycle; /* cycle node */
92 struct _ftsent *fts_parent; /* parent directory */
93 struct _ftsent *fts_link; /* next file in directory */
94 int64_t fts_number; /* local numeric value */
95 #define fts_bignum fts_number /* XXX non-std, should go away */
96 void *fts_pointer; /* local address value */
97 char *fts_accpath; /* access path */
98 char *fts_path; /* root path */
99 int fts_errno; /* errno for this node */
100 fts_fd_t fts_symfd; /* NT: Normally -1; -2 we followed this symlinked dir */
101 fts_fd_t fts_dirfd; /* NT: Handle to the directory (NT_FTS_)INVALID_HANDLE_VALUE if not valid */
102 size_t fts_pathlen; /* strlen(fts_path) */
103 size_t fts_namelen; /* strlen(fts_name) */
104
105 fts_ino_t fts_ino; /* inode */
106 fts_dev_t fts_dev; /* device */
107 fts_nlink_t fts_nlink; /* link count */
108
109 #define FTS_ROOTPARENTLEVEL -1
110 #define FTS_ROOTLEVEL 0
111 long fts_level; /* depth (-1 to N) */
112
113 #define FTS_D 1 /* preorder directory */
114 #define FTS_DC 2 /* directory that causes cycles */
115 #define FTS_DEFAULT 3 /* none of the above */
116 #define FTS_DNR 4 /* unreadable directory */
117 #define FTS_DOT 5 /* dot or dot-dot */
118 #define FTS_DP 6 /* postorder directory */
119 #define FTS_ERR 7 /* error; errno is set */
120 #define FTS_F 8 /* regular file */
121 #define FTS_INIT 9 /* initialized only */
122 #define FTS_NS 10 /* stat(2) failed */
123 #define FTS_NSOK 11 /* no stat(2) requested */
124 #define FTS_SL 12 /* symbolic link */
125 #define FTS_SLNONE 13 /* symbolic link without target */
126 //#define FTS_W 14 /* whiteout object */
127 int fts_info; /* user status for FTSENT structure */
128
129 #define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
130 #define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
131 #define FTS_ISW 0x04 /* this is a whiteout object */
132 unsigned fts_flags; /* private flags for FTSENT structure */
133
134 #define FTS_AGAIN 1 /* read node again */
135 #define FTS_FOLLOW 2 /* follow symbolic link */
136 #define FTS_NOINSTR 3 /* no instructions */
137 #define FTS_SKIP 4 /* discard node */
138 int fts_instr; /* fts_set() instructions */
139
140 struct stat *fts_statp; /* stat(2) information */
141 char *fts_name; /* file name */
142 FTS *fts_fts; /* back pointer to main FTS */
143 BirdStat_T fts_stat; /* NT: We always got stat info. */
144 } FTSENT;
145
146
147 #ifdef __cplusplus
148 extern "C" {
149 #endif
150
151 FTSENT *FTSCALL nt_fts_children(FTS *, int);
152 int FTSCALL nt_fts_close(FTS *);
153 void *FTSCALL nt_fts_get_clientptr(FTS *);
154 #define fts_get_clientptr(fts) ((fts)->fts_clientptr)
155 FTS *FTSCALL nt_fts_get_stream(FTSENT *);
156 #define fts_get_stream(ftsent) ((ftsent)->fts_fts)
157 FTS *FTSCALL nt_fts_open(char * const *, int,
158 int (FTSCALL*)(const FTSENT * const *, const FTSENT * const *));
159 FTSENT *FTSCALL nt_fts_read(FTS *);
160 int FTSCALL nt_fts_set(FTS *, FTSENT *, int);
161 void FTSCALL nt_fts_set_clientptr(FTS *, void *);
162
163 /* API mappings. */
164 #define fts_children(a_pFts, a_iInstr) nt_fts_children(a_pFts, a_iInstr)
165 #define fts_close(a_pFts) nt_fts_close(a_pFts)
166 #define fts_open(a_papszArgs, a_fOptions, a_pfnCompare) nt_fts_open(a_papszArgs, a_fOptions, a_pfnCompare)
167 #define fts_read(a_pFts) nt_fts_read(a_pFts)
168 #define fts_set(a_pFts, a_pFtsEntry, a_iInstr) nt_fts_set(a_pFts, a_pFtsEntry, a_iInstr)
169 #define fts_set_clientptr(a_pFts, a_pvUser) nt_fts_set_clientptr(a_pFts, a_pvUser)
170
171 #ifdef __cplusplus
172 }
173 #endif
174
175 #endif /* !INCLUDED_FTS_NT_H */
176
0 /* $Id: kFsCache.c 2879 2016-09-05 20:14:21Z bird $ */
0 /* $Id: kFsCache.c 2985 2016-11-01 18:26:35Z bird $ */
11 /** @file
22 * ntdircache.c - NT directory content cache.
33 */
3939 #include <stdio.h>
4040 #include <mbstring.h>
4141 #include <wchar.h>
42 //#include <intrin.h>
42 #ifdef _MSC_VER
43 # include <intrin.h>
44 #endif
4345 //#include <setjmp.h>
4446 //#include <ctype.h>
4547
8587 typedef KFSDIRREPOP *PKFSDIRREPOP;
8688
8789
90
91 /*********************************************************************************************************************************
92 * Internal Functions *
93 *********************************************************************************************************************************/
94 static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError);
8895
8996
9097 /**
198205 * @param pchString Pointer to the substring (not terminated).
199206 * @param cchString The length of the substring.
200207 */
201 static KU32 kFsCacheStrHashN(const char *pszString, KSIZE cchString)
208 static KU32 kFsCacheStrHashN(const char *pchString, KSIZE cchString)
202209 {
203210 KU32 uHash = 0;
204211 while (cchString-- > 0)
205212 {
206 KU32 uChar = (unsigned char)*pszString++;
213 KU32 uChar = (unsigned char)*pchString++;
207214 uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
208215 }
209216 return uHash;
586593 pObj->abUnused[1] = K_FALSE;
587594 pObj->fFlags = pParent->Obj.fFlags & KFSOBJ_F_INHERITED_MASK;
588595 pObj->pParent = pParent;
596 pObj->uNameHash = 0;
597 pObj->pNextNameHash = NULL;
598 pObj->pNameAlloc = NULL;
589599 pObj->pUserDataHead = NULL;
590600
591601 #ifdef KFSCACHE_CFG_UTF16
635645 kHlpAssert(pbExtra - (KU8 *)pObj == cbObj);
636646
637647 /*
638 * Type specific initilization.
648 * Type specific initialization.
639649 */
640650 if (fDirish)
641651 {
643653 pDirObj->cChildren = 0;
644654 pDirObj->cChildrenAllocated = 0;
645655 pDirObj->papChildren = NULL;
646 pDirObj->cHashTab = 0;
647 pDirObj->paHashTab = NULL;
656 pDirObj->fHashTabMask = 0;
657 pDirObj->papHashTab = NULL;
648658 pDirObj->hDir = INVALID_HANDLE_VALUE;
649659 pDirObj->uDevNo = pParent->uDevNo;
650660 pDirObj->iLastWrite = 0;
793803 return NULL;
794804 }
795805
806
807 /**
808 * Does the growing of names.
809 *
810 * @returns pCur
811 * @param pCache The cache.
812 * @param pCur The object.
813 * @param pchName The name (not necessarily terminated).
814 * @param cchName Name length.
815 * @param pwcName The UTF-16 name (not necessarily terminated).
816 * @param cwcName The length of the UTF-16 name in wchar_t's.
817 * @param pchShortName The short name.
818 * @param cchShortName The length of the short name. This is 0 if no short
819 * name.
820 * @param pwcShortName The short UTF-16 name.
821 * @param cwcShortName The length of the short UTF-16 name. This is 0 if
822 * no short name.
823 */
824 static PKFSOBJ kFsCacheRefreshGrowNames(PKFSCACHE pCache, PKFSOBJ pCur,
825 const char *pchName, KU32 cchName,
826 wchar_t const *pwcName, KU32 cwcName
827 #ifdef KFSCACHE_CFG_SHORT_NAMES
828 , const char *pchShortName, KU32 cchShortName,
829 wchar_t const *pwcShortName, KU32 cwcShortName
830 #endif
831 )
832 {
833 PKFSOBJNAMEALLOC pNameAlloc;
834 char *pch;
835 KU32 cbNeeded;
836
837 pCache->cNameGrowths++;
838
839 /*
840 * Figure out our requirements.
841 */
842 cbNeeded = sizeof(KU32) + cchName + 1;
843 #ifdef KFSCACHE_CFG_UTF16
844 cbNeeded += (cwcName + 1) * sizeof(wchar_t);
845 #endif
846 #ifdef KFSCACHE_CFG_SHORT_NAMES
847 cbNeeded += cchShortName + !!cchShortName;
848 # ifdef KFSCACHE_CFG_UTF16
849 cbNeeded += (cwcShortName + !!cwcShortName) * sizeof(wchar_t);
850 # endif
851 #endif
852 cbNeeded = K_ALIGN_Z(cbNeeded, 8); /* Memory will likely be 8 or 16 byte aligned, so we might just claim it. */
853
854 /*
855 * Allocate memory.
856 */
857 pNameAlloc = pCur->pNameAlloc;
858 if (!pNameAlloc)
859 {
860 pNameAlloc = (PKFSOBJNAMEALLOC)kHlpAlloc(cbNeeded);
861 if (!pNameAlloc)
862 return pCur;
863 pCache->cbObjects += cbNeeded;
864 pCur->pNameAlloc = pNameAlloc;
865 pNameAlloc->cb = cbNeeded;
866 }
867 else if (pNameAlloc->cb < cbNeeded)
868 {
869 pNameAlloc = (PKFSOBJNAMEALLOC)kHlpRealloc(pNameAlloc, cbNeeded);
870 if (!pNameAlloc)
871 return pCur;
872 pCache->cbObjects += cbNeeded - pNameAlloc->cb;
873 pCur->pNameAlloc = pNameAlloc;
874 pNameAlloc->cb = cbNeeded;
875 }
876
877 /*
878 * Copy out the new names, starting with the wide char ones to avoid misaligning them.
879 */
880 pch = &pNameAlloc->abSpace[0];
881
882 #ifdef KFSCACHE_CFG_UTF16
883 pCur->pwszName = (wchar_t *)pch;
884 pCur->cwcName = cwcName;
885 pch = kHlpMemPCopy(pch, pwcName, cwcName * sizeof(wchar_t));
886 *pch++ = '\0';
887 *pch++ = '\0';
888
889 # ifdef KFSCACHE_CFG_SHORT_NAMES
890 if (cwcShortName == 0)
891 {
892 pCur->pwszShortName = pCur->pwszName;
893 pCur->cwcShortName = pCur->cwcName;
894 }
895 else
896 {
897 pCur->pwszShortName = (wchar_t *)pch;
898 pCur->cwcShortName = cwcShortName;
899 pch = kHlpMemPCopy(pch, pwcShortName, cwcShortName * sizeof(wchar_t));
900 *pch++ = '\0';
901 *pch++ = '\0';
902 }
903 # endif
904 #endif
905
906 pCur->pszName = pch;
907 pCur->cchName = cchName;
908 pch = kHlpMemPCopy(pch, pchName, cchShortName);
909 *pch++ = '\0';
910
911 #ifdef KFSCACHE_CFG_SHORT_NAMES
912 if (cchShortName == 0)
913 {
914 pCur->pszShortName = pCur->pszName;
915 pCur->cchShortName = pCur->cchName;
916 }
917 else
918 {
919 pCur->pszShortName = pch;
920 pCur->cchShortName = cchShortName;
921 pch = kHlpMemPCopy(pch, pchShortName, cchShortName);
922 *pch++ = '\0';
923 }
924 #endif
925
926 return pCur;
927 }
928
929
796930 /**
797931 * Worker for kFsCacheDirFindOldChild that refreshes the file ID value on an
798932 * object found by name.
799933 *
800 * @returns Pointer to the existing object if found, NULL if not.
934 * @returns pCur.
801935 * @param pDirRePop Repopulation data.
802936 * @param pCur The object to check the names of.
803937 * @param idFile The file ID.
817951 * Worker for kFsCacheDirFindOldChild that checks the names after an old object
818952 * has been found the file ID.
819953 *
820 * @returns Pointer to the existing object if found, NULL if not.
954 * @returns pCur.
821955 * @param pDirRePop Repopulation data.
822956 * @param pCur The object to check the names of.
823957 * @param pwcName The file name.
831965 #endif
832966 )
833967 {
968 char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
969 int cchName;
970
971 pDirRePop->pCache->cNameChanges++;
972
834973 /*
835974 * Convert the names to ANSI first, that way we know all the lengths.
836975 */
837 char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
838 int cchName = WideCharToMultiByte(CP_ACP, 0, pwcName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
976 cchName = WideCharToMultiByte(CP_ACP, 0, pwcName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
839977 if (cchName >= 0)
840978 {
841979 #ifdef KFSCACHE_CFG_SHORT_NAMES
9051043 return pCur;
9061044 }
9071045 }
908 }
909 }
910
911
912 fprintf(stderr,
913 "kFsCacheDirRefreshOldChildName - not implemented!\n"
914 " Old name: %#x '%ls'\n"
915 " New name: %#x '%*.*ls'\n"
916 " Old short: %#x '%ls'\n"
917 " New short: %#x '%*.*ls'\n",
918 pCur->cwcName, pCur->pwszName,
919 cwcName, cwcName, cwcName, pwcName,
920 pCur->cwcShortName, pCur->pwszShortName,
921 cwcShortName, cwcShortName, cwcShortName, pwcShortName);
922 __debugbreak();
923 /** @todo implement this. It's not entirely straight forward, especially if
924 * the name increases! Also, it's something that may happend during
925 * individual object refresh and we might want to share code... */
926
1046
1047 return kFsCacheRefreshGrowNames(pDirRePop->pCache, pCur, szName, cchName, pwcName, cwcName,
1048 #ifdef KFSCACHE_CFG_SHORT_NAMES
1049 szShortName, cchShortName, pwcShortName, cwcShortName
1050 #endif
1051 );
1052 }
1053 }
1054
1055 fprintf(stderr, "kFsCacheDirRefreshOldChildName: WideCharToMultiByte error\n");
9271056 return pCur;
9281057 }
9291058
9301059
9311060 /**
9321061 * Worker for kFsCacheDirFindOldChild that checks the names after an old object
933 * has been found the file ID.
934 *
935 * @returns Pointer to the existing object if found, NULL if not.
1062 * has been found by the file ID.
1063 *
1064 * @returns pCur.
9361065 * @param pDirRePop Repopulation data.
9371066 * @param pCur The object to check the names of.
9381067 * @param pwcName The file name.
11081237 KU32 cOldChildren = pDirRePop->cOldChildren;
11091238 if (cOldChildren > 0)
11101239 {
1111 KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren);
1240 KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1);
11121241 PKFSOBJ pCur = pDirRePop->papOldChildren[iNextOldChild];
11131242
11141243 if ( pCur->Stats.st_ino == idFile
12511380 */
12521381 else if (pDir->fPopulated)
12531382 {
1254 KU32 cAllocated = K_ALIGN_Z(pDir->cChildren, 16);
1255 void *pvNew = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated);
1383 KU32 cAllocated;
1384 void *pvNew;
1385
1386 /* Make sure we really need to do this first. */
1387 if (!pDir->fNeedRePopulating)
1388 {
1389 if ( pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
1390 || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
1391 return K_TRUE;
1392 if ( kFsCacheRefreshObj(pCache, &pDir->Obj, penmError)
1393 && !pDir->fNeedRePopulating)
1394 return K_TRUE;
1395 }
1396
1397 /* Yes we do need to. */
1398 cAllocated = K_ALIGN_Z(pDir->cChildren, 16);
1399 pvNew = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated);
12561400 if (pvNew)
12571401 {
12581402 DirRePop.papOldChildren = pDir->papChildren;
15141658 KFSCACHE_LOG(("Refreshing %s/%s/ - %s was removed.\n",
15151659 pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pOldChild->pszName));
15161660 kHlpAssert(pOldChild->bObjType != KFSOBJ_TYPE_DIR);
1661 /* Remove from hash table. */
1662 if (pOldChild->uNameHash != 0)
1663 {
1664 KU32 idx = pOldChild->uNameHash & pDir->fHashTabMask;
1665 PKFSOBJ pPrev = pDir->papHashTab[idx];
1666 if (pPrev == pOldChild)
1667 pDir->papHashTab[idx] = pOldChild->pNextNameHash;
1668 else
1669 {
1670 while (pPrev && pPrev->pNextNameHash != pOldChild)
1671 pPrev = pPrev->pNextNameHash;
1672 kHlpAssert(pPrev);
1673 if (pPrev)
1674 pPrev->pNextNameHash = pOldChild->pNextNameHash;
1675 }
1676 pOldChild->uNameHash = 0;
1677 }
15171678 }
15181679 kFsCacheObjRelease(pCache, pOldChild);
15191680 }
15851746 if ( pDir->hDir != INVALID_HANDLE_VALUE
15861747 && (pDir->Obj.fFlags & KFSOBJ_F_WORKING_DIR_MTIME) )
15871748 {
1588 MY_IO_STATUS_BLOCK Ios;
1589 MY_FILE_BASIC_INFORMATION BasicInfo;
1590 MY_NTSTATUS rcNt;
1591
1592 Ios.Information = -1;
1593 Ios.u.Status = -1;
1594
1595 rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
1596 if (MY_NT_SUCCESS(rcNt))
1597 return BasicInfo.LastWriteTime.QuadPart != pDir->iLastWrite;
1749 if (!pDir->fNeedRePopulating)
1750 {
1751 MY_IO_STATUS_BLOCK Ios;
1752 MY_FILE_BASIC_INFORMATION BasicInfo;
1753 MY_NTSTATUS rcNt;
1754
1755 Ios.Information = -1;
1756 Ios.u.Status = -1;
1757
1758 rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
1759 if (MY_NT_SUCCESS(rcNt))
1760 {
1761 if (BasicInfo.LastWriteTime.QuadPart != pDir->iLastWrite)
1762 {
1763 pDir->fNeedRePopulating = K_TRUE;
1764 return K_TRUE;
1765 }
1766 return K_FALSE;
1767 }
1768 }
15981769 }
15991770 /* The cache root never changes. */
16001771 else if (!pDir->Obj.pParent)
18091980 KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx and names too...\n",
18101981 pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart));
18111982 fprintf(stderr, "kFsCacheRefreshObj - ID + name change not implemented!!\n");
1983 fflush(stderr);
18121984 __debugbreak();
18131985 pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart;
18141986 /** @todo implement as needed. */
18942066 /* ouch! */
18952067 kHlpAssertMsgFailed(("%#x\n", rcNt));
18962068 fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on dir - not implemented!\n", rcNt);
2069 fflush(stderr);
18972070 __debugbreak();
18982071 fRc = K_FALSE;
18992072 }
19142087 * missing node.
19152088 * @param pCache The cache.
19162089 * @param chLetter The uppercased drive letter.
2090 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
19172091 * @param penmError Where to return details as to why the lookup
19182092 * failed.
19192093 */
1920 static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPERROR *penmError)
1921 {
1922 KU32 const uHash = chLetter - 'A';
2094 static PKFSOBJ kFsCacheLookupDrive(PKFSCACHE pCache, char chLetter, KU32 fFlags, KFSLOOKUPERROR *penmError)
2095 {
2096 KU32 const uNameHash = chLetter - 'A';
2097 PKFSOBJ pCur = pCache->RootDir.papHashTab[uNameHash];
2098
19232099 KU32 cLeft;
19242100 PKFSOBJ *ppCur;
1925
19262101 MY_UNICODE_STRING NtPath;
19272102 wchar_t wszTmp[8];
19282103 char szTmp[4];
19302105 /*
19312106 * Custom drive letter hashing.
19322107 */
1933 if (pCache->RootDir.paHashTab)
1934 {
1935 /** @todo PKFSOBJHASH pHash = */
2108 kHlpAssert((uNameHash & pCache->RootDir.fHashTabMask) == uNameHash);
2109 while (pCur)
2110 {
2111 if ( pCur->uNameHash == uNameHash
2112 && pCur->cchName == 2
2113 && pCur->pszName[0] == chLetter
2114 && pCur->pszName[1] == ':')
2115 {
2116 if (pCur->bObjType == KFSOBJ_TYPE_DIR)
2117 return pCur;
2118 if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
2119 || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
2120 return pCur;
2121 return NULL;
2122 }
2123 pCur = pCur->pNextNameHash;
19362124 }
19372125
19382126 /*
1939 * Special cased lookup.
2127 * Make 100% sure it's not there.
19402128 */
19412129 cLeft = pCache->RootDir.cChildren;
19422130 ppCur = pCache->RootDir.papChildren;
19432131 while (cLeft-- > 0)
19442132 {
1945 PKFSOBJ pCur = *ppCur++;
2133 pCur = *ppCur++;
19462134 if ( pCur->cchName == 2
19472135 && pCur->pszName[0] == chLetter
19482136 && pCur->pszName[1] == ':')
19502138 if (pCur->bObjType == KFSOBJ_TYPE_DIR)
19512139 return pCur;
19522140 kHlpAssert(pCur->bObjType == KFSOBJ_TYPE_MISSING);
1953 if (kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
2141 if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
2142 || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
19542143 return pCur;
19552144 return NULL;
19562145 }
2146 }
2147
2148 if (fFlags & KFSCACHE_LOOKUP_F_NO_INSERT)
2149 {
2150 *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; /* close enough */
2151 return NULL;
19572152 }
19582153
19592154 /*
19742169 {
19752170 HANDLE hDir;
19762171 MY_NTSTATUS rcNt;
1977 rcNt = birdOpenFileUniStr(&NtPath,
2172 rcNt = birdOpenFileUniStr(NULL /*hRoot*/,
2173 &NtPath,
19782174 FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
19792175 FILE_ATTRIBUTE_NORMAL,
19802176 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
20492245 */
20502246 fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, &pDir->Obj, penmError);
20512247 kFsCacheObjRelease(pCache, &pDir->Obj);
2052 return fRc ? &pDir->Obj : NULL;
2248 if (fRc)
2249 {
2250 pDir->Obj.pNextNameHash = pCache->RootDir.papHashTab[uNameHash];
2251 pCache->RootDir.papHashTab[uNameHash] = &pDir->Obj;
2252 return &pDir->Obj;
2253 }
2254 return NULL;
20532255 }
20542256
20552257 g_pfnNtClose(hDir);
21002302
21012303
21022304 /**
2305 * Slow path that allocates the child hash table and enters the given one.
2306 *
2307 * Allocation fialures are ignored.
2308 *
2309 * @param pCache The cache (for stats).
2310 * @param pDir The directory.
2311 * @param uNameHash The name hash to enter @a pChild under.
2312 * @param pChild The child to enter into the hash table.
2313 */
2314 static void kFsCacheDirAllocHashTabAndEnterChild(PKFSCACHE pCache, PKFSDIR pDir, KU32 uNameHash, PKFSOBJ pChild)
2315 {
2316 if (uNameHash != 0) /* paranoia ^ 4! */
2317 {
2318 /*
2319 * Double the current number of children and round up to a multiple of
2320 * two so we can avoid division.
2321 */
2322 KU32 cbHashTab;
2323 KU32 cEntries;
2324 kHlpAssert(pDir->cChildren > 0);
2325 if (pDir->cChildren <= KU32_MAX / 4)
2326 {
2327 #if defined(_MSC_VER) && 1
2328 KU32 cEntriesRaw = pDir->cChildren * 2;
2329 KU32 cEntriesShift;
2330 kHlpAssert(sizeof(cEntries) == (unsigned long));
2331 if (_BitScanReverse(&cEntriesShift, cEntriesRaw))
2332 {
2333 if ( K_BIT32(cEntriesShift) < cEntriesRaw
2334 && cEntriesShift < 31U)
2335 cEntriesShift++;
2336 cEntries = K_BIT32(cEntriesShift);
2337 }
2338 else
2339 {
2340 kHlpAssertFailed();
2341 cEntries = KU32_MAX / 2 + 1;
2342 }
2343 #else
2344 cEntries = pDir->cChildren * 2 - 1;
2345 cEntries |= cEntries >> 1;
2346 cEntries |= cEntries >> 2;
2347 cEntries |= cEntries >> 4;
2348 cEntries |= cEntries >> 8;
2349 cEntries |= cEntries >> 16;
2350 cEntries++;
2351 #endif
2352 }
2353 else
2354 cEntries = KU32_MAX / 2 + 1;
2355 kHlpAssert((cEntries & (cEntries - 1)) == 0);
2356
2357 cbHashTab = cEntries * sizeof(pDir->papHashTab[0]);
2358 pDir->papHashTab = (PKFSOBJ *)kHlpAllocZ(cbHashTab);
2359 if (pDir->papHashTab)
2360 {
2361 KU32 idx;
2362 pDir->fHashTabMask = cEntries - 1;
2363 pCache->cbObjects += cbHashTab;
2364 pCache->cChildHashTabs++;
2365 pCache->cChildHashEntriesTotal += cEntries;
2366
2367 /*
2368 * Insert it.
2369 */
2370 pChild->uNameHash = uNameHash;
2371 idx = uNameHash & (pDir->fHashTabMask);
2372 pChild->pNextNameHash = pDir->papHashTab[idx];
2373 pDir->papHashTab[idx] = pChild;
2374 pCache->cChildHashed++;
2375 }
2376 }
2377 }
2378
2379
2380 /**
21032381 * Look up a child node, ANSI version.
21042382 *
21052383 * @returns Pointer to the child if found, NULL if not.
21102388 */
21112389 static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName)
21122390 {
2113 /* Check for '.' first. */
2391 /*
2392 * Check for '.' first ('..' won't appear).
2393 */
21142394 if (cchName != 1 || *pchName != '.')
21152395 {
2396 PKFSOBJ *ppCur;
21162397 KU32 cLeft;
2117 PKFSOBJ *ppCur;
2118
2119 if (pParent->paHashTab != NULL)
2120 {
2121 /** @todo directory hash table lookup. */
2122 }
2123
2124 /* Linear search. */
2398 KU32 uNameHash;
2399
2400 /*
2401 * Do hash table lookup.
2402 *
2403 * This caches previous lookups, which should be useful when looking up
2404 * intermediate directories at least.
2405 */
2406 if (pParent->papHashTab != NULL)
2407 {
2408 PKFSOBJ pCur;
2409 uNameHash = kFsCacheStrHashN(pchName, cchName);
2410 pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask];
2411 while (pCur)
2412 {
2413 if ( pCur->uNameHash == uNameHash
2414 && ( ( pCur->cchName == cchName
2415 && _mbsnicmp(pCur->pszName, pchName, cchName) == 0)
2416 #ifdef KFSCACHE_CFG_SHORT_NAMES
2417 || ( pCur->cchShortName == cchName
2418 && pCur->pszShortName != pCur->pszName
2419 && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0)
2420 #endif
2421 )
2422 )
2423 {
2424 pCache->cChildHashHits++;
2425 pCache->cChildSearches++;
2426 return pCur;
2427 }
2428 pCur = pCur->pNextNameHash;
2429 }
2430 }
2431 else
2432 uNameHash = 0;
2433
2434 /*
2435 * Do linear search.
2436 */
21252437 cLeft = pParent->cChildren;
21262438 ppCur = pParent->papChildren;
21272439 while (cLeft-- > 0)
21352447 && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0)
21362448 #endif
21372449 )
2450 {
2451 /*
2452 * Consider entering it into the parent hash table.
2453 * Note! We hash the input, not the name we found.
2454 */
2455 if ( pCur->uNameHash == 0
2456 && pParent->cChildren >= 2)
2457 {
2458 if (pParent->papHashTab)
2459 {
2460 if (uNameHash != 0)
2461 {
2462 KU32 idxNameHash = uNameHash & pParent->fHashTabMask;
2463 pCur->uNameHash = uNameHash;
2464 pCur->pNextNameHash = pParent->papHashTab[idxNameHash];
2465 pParent->papHashTab[idxNameHash] = pCur;
2466 if (pCur->pNextNameHash)
2467 pCache->cChildHashCollisions++;
2468 pCache->cChildHashed++;
2469 }
2470 }
2471 else
2472 kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheStrHashN(pchName, cchName), pCur);
2473 }
2474
2475 pCache->cChildSearches++;
21382476 return pCur;
2139 }
2477 }
2478 }
2479
2480 pCache->cChildSearches++;
21402481 return NULL;
21412482 }
21422483 return &pParent->Obj;
21542495 */
21552496 static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName)
21562497 {
2157 /* Check for '.' first. */
2498 /*
2499 * Check for '.' first ('..' won't appear).
2500 */
21582501 if (cwcName != 1 || *pwcName != '.')
21592502 {
2503 PKFSOBJ *ppCur;
21602504 KU32 cLeft;
2161 PKFSOBJ *ppCur;
2162
2163 if (pParent->paHashTab != NULL)
2164 {
2165 /** @todo directory hash table lookup. */
2166 }
2167
2168 /* Linear search. */
2505 KU32 uNameHash;
2506
2507 /*
2508 * Do hash table lookup.
2509 *
2510 * This caches previous lookups, which should be useful when looking up
2511 * intermediate directories at least.
2512 */
2513 if (pParent->papHashTab != NULL)
2514 {
2515 PKFSOBJ pCur;
2516 uNameHash = kFsCacheUtf16HashN(pwcName, cwcName);
2517 pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask];
2518 while (pCur)
2519 {
2520 if ( pCur->uNameHash == uNameHash
2521 && ( ( pCur->cwcName == cwcName
2522 && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName))
2523 #ifdef KFSCACHE_CFG_SHORT_NAMES
2524 || ( pCur->cwcShortName == cwcName
2525 && pCur->pwszShortName != pCur->pwszName
2526 && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
2527 #endif
2528 )
2529 )
2530 {
2531 pCache->cChildHashHits++;
2532 pCache->cChildSearches++;
2533 return pCur;
2534 }
2535 pCur = pCur->pNextNameHash;
2536 }
2537 }
2538 else
2539 uNameHash = 0;
2540
2541 /*
2542 * Do linear search.
2543 */
21692544 cLeft = pParent->cChildren;
21702545 ppCur = pParent->papChildren;
21712546 while (cLeft-- > 0)
21792554 && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
21802555 #endif
21812556 )
2557 {
2558 /*
2559 * Consider entering it into the parent hash table.
2560 * Note! We hash the input, not the name we found.
2561 */
2562 if ( pCur->uNameHash == 0
2563 && pParent->cChildren >= 4)
2564 {
2565 if (pParent->papHashTab)
2566 {
2567 if (uNameHash != 0)
2568 {
2569 KU32 idxNameHash = uNameHash & pParent->fHashTabMask;
2570 pCur->uNameHash = uNameHash;
2571 pCur->pNextNameHash = pParent->papHashTab[idxNameHash];
2572 pParent->papHashTab[idxNameHash] = pCur;
2573 if (pCur->pNextNameHash)
2574 pCache->cChildHashCollisions++;
2575 pCache->cChildHashed++;
2576 }
2577 }
2578 else
2579 kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheUtf16HashN(pwcName, cwcName), pCur);
2580 }
2581
2582 pCache->cChildSearches++;
21822583 return pCur;
2183 }
2584 }
2585 }
2586 pCache->cChildSearches++;
21842587 return NULL;
21852588 }
21862589 return &pParent->Obj;
21972600 * node.
21982601 * @param pCache The cache.
21992602 * @param pszPath The path.
2603 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
22002604 * @param poff Where to return the root dire.
22012605 * @param penmError Where to return details as to why the lookup
22022606 * failed.
22032607 */
2204 static PKFSOBJ kFswCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 *poff, KFSLOOKUPERROR *penmError)
2205 {
2608 static PKFSOBJ kFsCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 fFlags,
2609 KU32 *poff, KFSLOOKUPERROR *penmError)
2610 {
2611 /*
2612 * Special case: Long path prefix w/ drive letter following it.
2613 * Note! Must've been converted from wide char to ANSI.
2614 */
2615 if ( IS_SLASH(pszPath[0])
2616 && IS_SLASH(pszPath[1])
2617 && pszPath[2] == '?'
2618 && IS_SLASH(pszPath[3])
2619 && IS_ALPHA(pszPath[4])
2620 && pszPath[5] == ':'
2621 && IS_SLASH(pszPath[6]) )
2622 {
2623 *poff = 4 + 2;
2624 return kFsCacheLookupDrive(pCache, pszPath[4], fFlags, penmError);
2625 }
2626
22062627 #if 0 /* later */
22072628 KU32 offStartServer;
22082629 KU32 offEndServer;
22482669 * node.
22492670 * @param pCache The cache.
22502671 * @param pwszPath The path.
2251 * @param poff Where to return the root dire.
2672 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
2673 * @param poff Where to return the root dir.
22522674 * @param penmError Where to return details as to why the lookup
22532675 * failed.
22542676 */
2255 static PKFSOBJ kFswCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 *poff, KFSLOOKUPERROR *penmError)
2256 {
2677 static PKFSOBJ kFsCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 fFlags,
2678 KU32 *poff, KFSLOOKUPERROR *penmError)
2679 {
2680 /*
2681 * Special case: Long path prefix w/ drive letter following it.
2682 */
2683 if ( IS_SLASH(pwszPath[0])
2684 && IS_SLASH(pwszPath[1])
2685 && pwszPath[2] == '?'
2686 && IS_SLASH(pwszPath[3])
2687 && IS_ALPHA(pwszPath[4])
2688 && pwszPath[5] == ':'
2689 && IS_SLASH(pwszPath[6]) )
2690 {
2691 *poff = 4 + 2;
2692 return kFsCacheLookupDrive(pCache, (char)pwszPath[4], fFlags, penmError);
2693 }
2694
2695
22572696 #if 0 /* later */
22582697 KU32 offStartServer;
22592698 KU32 offEndServer;
23022741 * @param pParent The directory to start the lookup in.
23032742 * @param pszPath The path to walk.
23042743 * @param cchPath The length of the path.
2744 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
23052745 * @param penmError Where to return details as to why the lookup
23062746 * failed.
23072747 * @param ppLastAncestor Where to return the last parent element found
23082748 * (referenced) in case of error an path/file not
23092749 * found problem. Optional.
23102750 */
2311 PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath,
2751 PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags,
23122752 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
23132753 {
23142754 /*
23432783 /*
23442784 * Do we need to populate or refresh this directory first?
23452785 */
2346 if ( pParent->fPopulated
2786 if ( !pParent->fNeedRePopulating
2787 && pParent->fPopulated
23472788 && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
23482789 || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) )
23492790 { /* likely */ }
2350 else if (kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
2791 else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH))
2792 || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
23512793 { /* likely */ }
23522794 else
23532795 return NULL;
23632805 { /* probably likely */ }
23642806 else
23652807 {
2366 if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
2808 if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
2809 && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT))
23672810 pChild = kFsCacheCreateMissingA(pCache, pParent, &pszPath[off], offEnd - off, penmError);
23682811 if (cchSlashes == 0 || offEnd + cchSlashes >= cchPath)
23692812 {
23862829 if ( pChild->bObjType != KFSOBJ_TYPE_MISSING
23872830 || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
23882831 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
2832 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
23892833 || kFsCacheRefreshMissing(pCache, pChild, penmError) )
23902834 { /* likely */ }
23912835 else
24072851 return NULL;
24082852 }
24092853 else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
2410 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
2854 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
2855 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH))
24112856 {
24122857 *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
24132858 if (ppLastAncestor)
24422887 * @param pParent The directory to start the lookup in.
24432888 * @param pszPath The path to walk. No dot-dot bits allowed!
24442889 * @param cchPath The length of the path.
2890 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
24452891 * @param penmError Where to return details as to why the lookup
24462892 * failed.
24472893 * @param ppLastAncestor Where to return the last parent element found
24482894 * (referenced) in case of error an path/file not
24492895 * found problem. Optional.
24502896 */
2451 PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath,
2897 PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
24522898 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
24532899 {
24542900 /*
24832929 /*
24842930 * Do we need to populate or refresh this directory first?
24852931 */
2486 if ( pParent->fPopulated
2932 if ( !pParent->fNeedRePopulating
2933 && pParent->fPopulated
24872934 && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
24882935 || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) )
24892936 { /* likely */ }
2490 else if (kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
2937 else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH))
2938 || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
24912939 { /* likely */ }
24922940 else
24932941 return NULL;
25032951 { /* probably likely */ }
25042952 else
25052953 {
2506 if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
2954 if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
2955 && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT))
25072956 pChild = kFsCacheCreateMissingW(pCache, pParent, &pwszPath[off], offEnd - off, penmError);
25082957 if (cwcSlashes == 0 || offEnd + cwcSlashes >= cwcPath)
25092958 {
25262975 if ( pChild->bObjType != KFSOBJ_TYPE_MISSING
25272976 || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
25282977 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
2978 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
25292979 || kFsCacheRefreshMissing(pCache, pChild, penmError) )
25302980 { /* likely */ }
25312981 else
25472997 return NULL;
25482998 }
25492999 else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
2550 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
3000 || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
3001 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) )
3002
25513003 {
25523004 *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
25533005 if (ppLastAncestor)
25813033 * @param pCache The cache.
25823034 * @param pszPath The path to walk. No dot-dot bits allowed!
25833035 * @param cchPath The length of the path.
3036 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
25843037 * @param penmError Where to return details as to why the lookup
25853038 * failed.
25863039 * @param ppLastAncestor Where to return the last parent element found
25873040 * (referenced) in case of error an path/file not
25883041 * found problem. Optional.
25893042 */
2590 static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath,
3043 static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags,
25913044 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
25923045 {
25933046 PKFSOBJ pRoot;
26073060 /* Drive letter. */
26083061 offEnd = 2;
26093062 kHlpAssert(IS_SLASH(pszPath[2]));
2610 pRoot = kFswCacheLookupDrive(pCache, toupper(pszPath[0]), penmError);
3063 pRoot = kFsCacheLookupDrive(pCache, toupper(pszPath[0]), fFlags, penmError);
26113064 }
26123065 else if ( IS_SLASH(pszPath[0])
26133066 && IS_SLASH(pszPath[1]) )
2614 pRoot = kFswCacheLookupUncShareA(pCache, pszPath, &offEnd, penmError);
3067 pRoot = kFsCacheLookupUncShareA(pCache, pszPath, fFlags, &offEnd, penmError);
26153068 else
26163069 {
26173070 *penmError = KFSLOOKUPERROR_UNSUPPORTED;
26383091 || pRoot->uCacheGen == ( pRoot->bObjType != KFSOBJ_TYPE_MISSING
26393092 ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
26403093 : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
3094 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
26413095 || kFsCacheRefreshObj(pCache, pRoot, penmError))
26423096 return kFsCacheObjRetainInternal(pRoot);
26433097 return NULL;
26593113 * remainder of the path starting with it.
26603114 */
26613115 return kFsCacheLookupRelativeToDirA(pCache, (PKFSDIR)pRoot, &pszPath[offEnd + cchSlashes],
2662 cchPath - offEnd - cchSlashes, penmError, ppLastAncestor);
3116 cchPath - offEnd - cchSlashes, fFlags, penmError, ppLastAncestor);
26633117 }
26643118
26653119
26753129 * @param pCache The cache.
26763130 * @param pwszPath The path to walk.
26773131 * @param cwcPath The length of the path (in wchar_t's).
3132 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
26783133 * @param penmError Where to return details as to why the lookup
26793134 * failed.
26803135 * @param ppLastAncestor Where to return the last parent element found
26813136 * (referenced) in case of error an path/file not
26823137 * found problem. Optional.
26833138 */
2684 static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath,
3139 static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
26853140 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
26863141 {
26873142 PKFSDIR pParent = &pCache->RootDir;
27043159 /* Drive letter. */
27053160 offEnd = 2;
27063161 kHlpAssert(IS_SLASH(pwszPath[2]));
2707 pRoot = kFswCacheLookupDrive(pCache, toupper(pwszPath[0]), penmError);
3162 pRoot = kFsCacheLookupDrive(pCache, toupper(pwszPath[0]), fFlags, penmError);
27083163 }
27093164 else if ( IS_SLASH(pwszPath[0])
27103165 && IS_SLASH(pwszPath[1]) )
2711 pRoot = kFswCacheLookupUncShareW(pCache, pwszPath, &offEnd, penmError);
3166 pRoot = kFsCacheLookupUncShareW(pCache, pwszPath, fFlags, &offEnd, penmError);
27123167 else
27133168 {
27143169 *penmError = KFSLOOKUPERROR_UNSUPPORTED;
27353190 || pRoot->uCacheGen == (pRoot->bObjType != KFSOBJ_TYPE_MISSING
27363191 ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
27373192 : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
3193 || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
27383194 || kFsCacheRefreshObj(pCache, pRoot, penmError))
27393195 return kFsCacheObjRetainInternal(pRoot);
27403196 return NULL;
27563212 * remainder of the path starting with it.
27573213 */
27583214 return kFsCacheLookupRelativeToDirW(pCache, (PKFSDIR)pRoot, &pwszPath[offEnd + cwcSlashes],
2759 cwcPath - offEnd - cwcSlashes, penmError, ppLastAncestor);
3215 cwcPath - offEnd - cwcSlashes, fFlags, penmError, ppLastAncestor);
27603216 }
27613217
27623218
27703226 * @param pCache The cache.
27713227 * @param pszPath The path.
27723228 * @param cchPath The length of the path.
3229 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
27733230 * @param penmError Where to return details as to why the lookup
27743231 * failed.
27753232 * @param ppLastAncestor Where to return the last parent element found
27763233 * (referenced) in case of error an path/file not
27773234 * found problem. Optional.
27783235 */
2779 static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath,
3236 static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags,
27803237 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
27813238 {
27823239 /*
27883245 if ( cchFull >= 3
27893246 && cchFull < sizeof(szFull))
27903247 {
2791 PKFSOBJ pFsObj;
27923248 KFSCACHE_LOG2(("kFsCacheLookupSlowA(%s)\n", pszPath));
2793 pFsObj = kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, penmError, ppLastAncestor);
2794
2795 #if 0 /* No need to do this until it's actually queried. */
2796 /* Cache the resulting path. */
2797 if ( pFsObj
2798 || (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
2799 || *penmError == KFSLOOKUPERROR_UNSUPPORTED)
2800 {
2801 KU32 uHashPath = kFsCacheStrHash(szFull);
2802 kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath,
2803 uHashPath % K_ELEMENTS(pCache->apAnsiPaths), *penmError);
2804 }
2805 #endif
2806 return pFsObj;
3249 return kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, fFlags, penmError, ppLastAncestor);
28073250 }
28083251
28093252 /* The path is too long! */
28233266 * @param pCache The cache.
28243267 * @param pwszPath The path.
28253268 * @param cwcPath The length of the path (in wchar_t's).
3269 * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
28263270 * @param penmError Where to return details as to why the lookup
28273271 * failed.
28283272 * @param ppLastAncestor Where to return the last parent element found
28293273 * (referenced) in case of error an path/file not
28303274 * found problem. Optional.
28313275 */
2832 static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath,
3276 static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath, KU32 fFlags,
28333277 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
28343278 {
28353279 /*
28413285 if ( cwcFull >= 3
28423286 && cwcFull < KFSCACHE_CFG_MAX_PATH)
28433287 {
2844 PKFSOBJ pFsObj;
28453288 KFSCACHE_LOG2(("kFsCacheLookupSlowA(%ls)\n", pwszPath));
2846 pFsObj = kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, penmError, ppLastAncestor);
2847
2848 #if 0 /* No need to do this until it's actually queried. */
2849 /* Cache the resulting path. */
2850 if ( pFsObj
2851 || (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
2852 || *penmError == KFSLOOKUPERROR_UNSUPPORTED)
2853 {
2854 KU32 uHashPath = kFsCacheStrHash(szFull);
2855 kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath,
2856 uHashPath % K_ELEMENTS(pCache->apAnsiPaths), *penmError);
2857 }
2858 #endif
2859 return pFsObj;
3289 return kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, fFlags, penmError, ppLastAncestor);
28603290 }
28613291
28623292 /* The path is too long! */
28803310 if (!pHashEntry->pFsObj)
28813311 {
28823312 if (pHashEntry->fAbsolute)
2883 pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
3313 pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
28843314 &pHashEntry->enmError, &pLastAncestor);
28853315 else
2886 pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
3316 pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
28873317 &pHashEntry->enmError, &pLastAncestor);
28883318 }
28893319 else
28983328 {
28993329 kFsCacheObjRelease(pCache, pHashEntry->pFsObj);
29003330 if (pHashEntry->fAbsolute)
2901 pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
3331 pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
29023332 &pHashEntry->enmError, &pLastAncestor);
29033333 else
2904 pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath,
3334 pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
29053335 &pHashEntry->enmError, &pLastAncestor);
29063336 }
29073337 }
29413371 if (!pHashEntry->pFsObj)
29423372 {
29433373 if (pHashEntry->fAbsolute)
2944 pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
3374 pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
29453375 &pHashEntry->enmError, &pLastAncestor);
29463376 else
2947 pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
3377 pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
29483378 &pHashEntry->enmError, &pLastAncestor);
29493379 }
29503380 else
29593389 {
29603390 kFsCacheObjRelease(pCache, pHashEntry->pFsObj);
29613391 if (pHashEntry->fAbsolute)
2962 pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
3392 pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
29633393 &pHashEntry->enmError, &pLastAncestor);
29643394 else
2965 pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath,
3395 pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
29663396 &pHashEntry->enmError, &pLastAncestor);
29673397 }
29683398 }
29693399 else
29703400 {
29713401 fprintf(stderr, "kFsCacheRefreshPathW - refresh failure handling not implemented!\n");
3402 fflush(stderr);
29723403 __debugbreak();
29733404 /** @todo just remove this entry. */
29743405 return NULL;
30673498 && IS_SLASH(pchPath[1]) ) )
30683499 && !kFsCacheHasDotDotA(pchPath, cchPath) )
30693500 {
3070 pFsObj = kFsCacheLookupAbsoluteA(pCache, pchPath, cchPath, penmError, &pLastAncestor);
3501 pFsObj = kFsCacheLookupAbsoluteA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor);
30713502 fAbsolute = K_TRUE;
30723503 }
30733504 else
30743505 {
3075 pFsObj = kFsCacheLookupSlowA(pCache, pchPath, cchPath, penmError, &pLastAncestor);
3506 pFsObj = kFsCacheLookupSlowA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor);
30763507 fAbsolute = K_FALSE;
30773508 }
30783509 if ( pFsObj
31753606 && IS_SLASH(pwcPath[1]) ) )
31763607 && !kFsCacheHasDotDotW(pwcPath, cwcPath) )
31773608 {
3178 pFsObj = kFsCacheLookupAbsoluteW(pCache, pwcPath, cwcPath, penmError, &pLastAncestor);
3609 pFsObj = kFsCacheLookupAbsoluteW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor);
31793610 fAbsolute = K_TRUE;
31803611 }
31813612 else
31823613 {
3183 pFsObj = kFsCacheLookupSlowW(pCache, pwcPath, cwcPath, penmError, &pLastAncestor);
3614 pFsObj = kFsCacheLookupSlowW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor);
31843615 fAbsolute = K_FALSE;
31853616 }
31863617 if ( pFsObj
33683799 * @returns 0
33693800 * @param pCache The cache.
33703801 * @param pObj The object.
3371 */
3372 KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
3802 * @param pszWhere Where it was released from.
3803 */
3804 KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere)
33733805 {
33743806 kHlpAssert(pObj->cRefs == 0);
33753807 kHlpAssert(pObj->pParent == NULL);
33763808 kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
33773809
3378 KFSCACHE_LOG(("Destroying %s/%s, type=%d\n", pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType));
3810 KFSCACHE_LOG(("Destroying %s/%s, type=%d, pObj=%p, pszWhere=%s\n",
3811 pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType, pObj, pszWhere));
33793812 if (pObj->abUnused[1] != 0)
33803813 {
33813814 fprintf(stderr, "Destroying %s/%s, type=%d, path hash entries: %d!\n", pObj->pParent ? pObj->pParent->Obj.pszName : "",
33823815 pObj->pszName, pObj->bObjType, pObj->abUnused[0]);
3816 fflush(stderr);
33833817 __debugbreak();
33843818 }
33853819
34163850 KU32 cChildren = pDir->cChildren;
34173851 pCache->cbObjects -= sizeof(*pDir)
34183852 + K_ALIGN_Z(cChildren, 16) * sizeof(pDir->papChildren)
3419 + pDir->cHashTab * sizeof(pDir->paHashTab);
3853 + (pDir->fHashTabMask + !!pDir->fHashTabMask) * sizeof(pDir->papHashTab[0]);
34203854
34213855 pDir->cChildren = 0;
34223856 while (cChildren-- > 0)
34243858 kHlpFree(pDir->papChildren);
34253859 pDir->papChildren = NULL;
34263860
3427 kHlpFree(pDir->paHashTab);
3428 pDir->paHashTab = NULL;
3861 kHlpFree(pDir->papHashTab);
3862 pDir->papHashTab = NULL;
34293863 break;
34303864 }
34313865
34563890 #endif
34573891 pCache->cObjects--;
34583892
3893 if (pObj->pNameAlloc)
3894 {
3895 pCache->cbObjects -= pObj->pNameAlloc->cb;
3896 kHlpFree(pObj->pNameAlloc);
3897 }
3898
34593899 kHlpFree(pObj);
34603900 return 0;
34613901 }
34683908 * @param pCache The cache.
34693909 * @param pObj The object.
34703910 */
3911 #undef kFsCacheObjRelease
34713912 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj)
34723913 {
34733914 if (pObj)
34793920 cRefs = --pObj->cRefs;
34803921 if (cRefs)
34813922 return cRefs;
3482 return kFsCacheObjDestroy(pCache, pObj);
3923 return kFsCacheObjDestroy(pCache, pObj, "kFsCacheObjRelease");
3924 }
3925 return 0;
3926 }
3927
3928
3929 /**
3930 * Debug version of kFsCacheObjRelease
3931 *
3932 * @returns New reference count.
3933 * @param pCache The cache.
3934 * @param pObj The object.
3935 * @param pszWhere Where it's invoked from.
3936 */
3937 KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere)
3938 {
3939 if (pObj)
3940 {
3941 KU32 cRefs;
3942 kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
3943 kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
3944
3945 cRefs = --pObj->cRefs;
3946 if (cRefs)
3947 return cRefs;
3948 return kFsCacheObjDestroy(pCache, pObj, pszWhere);
34833949 }
34843950 return 0;
34853951 }
39784444 pRoot->fFlags |= KFSOBJ_F_USE_CUSTOM_GEN;
39794445 return K_TRUE;
39804446 }
4447 return K_FALSE;
4448 }
4449
4450
4451 /**
4452 * Invalidates a deleted directory, ANSI version.
4453 *
4454 * @returns K_TRUE if found and is a non-root directory. Otherwise K_FALSE.
4455 * @param pCache The cache.
4456 * @param pszDir The directory.
4457 */
4458 KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir)
4459 {
4460 KU32 cchDir = (KU32)kHlpStrLen(pszDir);
4461 KFSLOOKUPERROR enmError;
4462 PKFSOBJ pFsObj;
4463
4464 /* Is absolute without any '..' bits? */
4465 if ( cchDir >= 3
4466 && ( ( pszDir[1] == ':' /* Drive letter */
4467 && IS_SLASH(pszDir[2])
4468 && IS_ALPHA(pszDir[0]) )
4469 || ( IS_SLASH(pszDir[0]) /* UNC */
4470 && IS_SLASH(pszDir[1]) ) )
4471 && !kFsCacheHasDotDotA(pszDir, cchDir) )
4472 pFsObj = kFsCacheLookupAbsoluteA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH,
4473 &enmError, NULL);
4474 else
4475 pFsObj = kFsCacheLookupSlowA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH,
4476 &enmError, NULL);
4477 if (pFsObj)
4478 {
4479 /* Is directory? */
4480 if (pFsObj->bObjType == KFSOBJ_TYPE_DIR)
4481 {
4482 if (pFsObj->pParent != &pCache->RootDir)
4483 {
4484 PKFSDIR pDir = (PKFSDIR)pFsObj;
4485 KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: %s hDir=%p\n", pszDir, pDir->hDir));
4486 if (pDir->hDir != INVALID_HANDLE_VALUE)
4487 {
4488 g_pfnNtClose(pDir->hDir);
4489 pDir->hDir = INVALID_HANDLE_VALUE;
4490 }
4491 pDir->fNeedRePopulating = K_TRUE;
4492 pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN] - 1;
4493 kFsCacheObjRetainInternal(&pDir->Obj);
4494 return K_TRUE;
4495 }
4496 KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a root directory was deleted! %s\n", pszDir));
4497 }
4498 else
4499 KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a non-directory: bObjType=%d %s\n",
4500 pFsObj->bObjType, pszDir));
4501 kFsCacheObjRetainInternal(pFsObj);
4502 }
4503 else
4504 KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: '%s' was not found\n", pszDir));
39814505 return K_FALSE;
39824506 }
39834507
40204544 pCache->RootDir.cChildrenAllocated = 0;
40214545 pCache->RootDir.papChildren = NULL;
40224546 pCache->RootDir.hDir = INVALID_HANDLE_VALUE;
4023 pCache->RootDir.cHashTab = 251;
4024 pCache->RootDir.paHashTab = (PKFSOBJHASH)kHlpAllocZ( pCache->RootDir.cHashTab
4025 * sizeof(pCache->RootDir.paHashTab[0]));
4026 if (pCache->RootDir.paHashTab)
4547 pCache->RootDir.fHashTabMask = 255; /* 256: 26 drive letters and 102 UNCs before we're half ways. */
4548 pCache->RootDir.papHashTab = (PKFSOBJ *)kHlpAllocZ(256 * sizeof(pCache->RootDir.papHashTab[0]));
4549 if (pCache->RootDir.papHashTab)
40274550 {
40284551 /* The cache itself. */
4029 pCache->u32Magic = KFSCACHE_MAGIC;
4030 pCache->fFlags = fFlags;
4552 pCache->u32Magic = KFSCACHE_MAGIC;
4553 pCache->fFlags = fFlags;
40314554 pCache->auGenerations[0] = KU32_MAX / 4;
40324555 pCache->auGenerations[1] = KU32_MAX / 32;
40334556 pCache->auGenerationsMissing[0] = KU32_MAX / 256;
40344557 pCache->auGenerationsMissing[1] = 1;
4035 pCache->cObjects = 1;
4036 pCache->cbObjects = sizeof(pCache->RootDir) + pCache->RootDir.cHashTab * sizeof(pCache->RootDir.paHashTab[0]);
4037 pCache->cPathHashHits = 0;
4038 pCache->cWalkHits = 0;
4039 pCache->cAnsiPaths = 0;
4040 pCache->cAnsiPathCollisions = 0;
4041 pCache->cbAnsiPaths = 0;
4558 pCache->cObjects = 1;
4559 pCache->cbObjects = sizeof(pCache->RootDir)
4560 + (pCache->RootDir.fHashTabMask + 1) * sizeof(pCache->RootDir.papHashTab[0]);
4561 pCache->cPathHashHits = 0;
4562 pCache->cWalkHits = 0;
4563 pCache->cChildSearches = 0;
4564 pCache->cChildHashHits = 0;
4565 pCache->cChildHashed = 0;
4566 pCache->cChildHashTabs = 1;
4567 pCache->cChildHashEntriesTotal = pCache->RootDir.fHashTabMask + 1;
4568 pCache->cChildHashCollisions = 0;
4569 pCache->cNameChanges = 0;
4570 pCache->cNameGrowths = 0;
4571 pCache->cAnsiPaths = 0;
4572 pCache->cAnsiPathCollisions = 0;
4573 pCache->cbAnsiPaths = 0;
40424574 #ifdef KFSCACHE_CFG_UTF16
4043 pCache->cUtf16Paths = 0;
4044 pCache->cUtf16PathCollisions = 0;
4045 pCache->cbUtf16Paths = 0;
4575 pCache->cUtf16Paths = 0;
4576 pCache->cUtf16PathCollisions = 0;
4577 pCache->cbUtf16Paths = 0;
40464578 #endif
40474579 return pCache;
40484580 }
0 /* $Id: kFsCache.h 2868 2016-09-04 01:28:12Z bird $ */
0 /* $Id: kFsCache.h 2967 2016-09-26 18:14:13Z bird $ */
11 /** @file
22 * kFsCache.c - NT directory content cache.
33 */
4646 #define KFSCACHE_CFG_SHORT_NAMES 1
4747 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE
4848 * Size of the path hash table. */
49 #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE 16381
49 #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE 99991
5050 /** The max length paths we consider. */
5151 #define KFSCACHE_CFG_MAX_PATH 1024
5252 /** The max ANSI name length. */
110110 typedef struct KFSOBJHASH *PKFSOBJHASH;
111111
112112
113 /**
114 * Directory hash table entry.
115 *
116 * There can be two of these per directory entry when the short name differs
117 * from the long name.
118 */
119 typedef struct KFSOBJHASH
120 {
121 /** Pointer to the next entry with the same hash. */
122 PKFSOBJHASH pNext;
123 /** Pointer to the object. */
124 PKFSOBJ pObj;
125 } KFSOBJHASH;
126
127113
128114 /** Pointer to a user data item. */
129115 typedef struct KFSUSERDATA *PKFSUSERDATA;
139125 /** The destructor. */
140126 void (*pfnDestructor)(PKFSCACHE pCache, PKFSOBJ pObj, PKFSUSERDATA pData);
141127 } KFSUSERDATA;
128
129
130 /**
131 * Storage for name strings for the unlikely event that they should grow in
132 * length after the KFSOBJ was created.
133 */
134 typedef struct KFSOBJNAMEALLOC
135 {
136 /** Size of the allocation. */
137 KU32 cb;
138 /** The space for names. */
139 char abSpace[1];
140 } KFSOBJNAMEALLOC;
141 /** Name growth allocation. */
142 typedef KFSOBJNAMEALLOC *PKFSOBJNAMEALLOC;
142143
143144
144145 /**
161162 /** Flags, KFSOBJ_F_XXX. */
162163 KU32 fFlags;
163164
165 /** Hash value of the name inserted into the parent hash table.
166 * This is 0 if not inserted. Names are only hashed and inserted as they are
167 * first found thru linear searching of its siblings, and which name it is
168 * dependens on the lookup function (W or A) and whether the normal name or
169 * short name seems to have matched.
170 *
171 * @note It was ruled out as too much work to hash and track all four names,
172 * so instead this minimalist approach was choosen in stead. */
173 KU32 uNameHash;
174 /** Pointer to the next child with the same name hash value. */
175 PKFSOBJ pNextNameHash;
164176 /** Pointer to the parent (directory).
165177 * This is only NULL for a root. */
166178 PKFSDIR pParent;
203215 # endif
204216 #endif
205217
218 /** Allocation for handling name length increases. */
219 PKFSOBJNAMEALLOC pNameAlloc;
220
206221 /** Pointer to the first user data item */
207222 PKFSUSERDATA pUserDataHead;
208223
229244 /** The allocated size of papChildren. */
230245 KU32 cChildrenAllocated;
231246
232 /** Pointer to the hash table.
233 * @todo this isn't quite there yet, structure wise. sigh. */
234 PKFSOBJHASH paHashTab;
235 /** The size of the hash table.
236 * @remarks The hash table is optional and only used when there are a lot of
237 * entries in the directory. */
238 KU32 cHashTab;
247 /** Pointer to the child hash table. */
248 PKFSOBJ *papHashTab;
249 /** The mask shift of the hash table.
250 * Hash table size is a power of two, this is the size minus one.
251 *
252 * @remarks The hash table is optional and populated by lookup hits. The
253 * assumption being that a lookup is repeated and will choose a good
254 * name to hash on. We've got up to 4 different hashes, so this
255 * was the easy way out. */
256 KU32 fHashTabMask;
239257
240258 /** Handle to the directory (we generally keep it open). */
241259 #ifndef DECLARE_HANDLE
399417 KSIZE cPathHashHits;
400418 /** Number of hits walking the file system hierarchy. */
401419 KSIZE cWalkHits;
420 /** Number of child searches. */
421 KSIZE cChildSearches;
422 /** Number of cChildLookups resolved thru hash table hits. */
423 KSIZE cChildHashHits;
424 /** The number of child hash tables. */
425 KSIZE cChildHashTabs;
426 /** The sum of all child hash table sizes. */
427 KSIZE cChildHashEntriesTotal;
428 /** Number of children inserted into the hash tables. */
429 KSIZE cChildHashed;
430 /** Number of collisions in the child hash tables. */
431 KSIZE cChildHashCollisions;
432 /** Number times a object name changed. */
433 KSIZE cNameChanges;
434 /** Number times a object name grew and needed KFSOBJNAMEALLOC.
435 * (Subset of cNameChanges) */
436 KSIZE cNameGrowths;
402437
403438 /** The root directory. */
404439 KFSDIR RootDir;
455490 KU8 bObjType, KFSLOOKUPERROR *penmError);
456491 PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError);
457492 PKFSOBJ kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError);
458 PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath,
493 PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags,
459494 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor);
460 PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath,
495 PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
461496 KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor);
462497 PKFSOBJ kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError);
463498 PKFSOBJ kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError);
464499 PKFSOBJ kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError);
465500 PKFSOBJ kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError);
466501
502 /** @name KFSCACHE_LOOKUP_F_XXX - lookup flags
503 * @{ */
504 /** No inserting new cache entries.
505 * This effectively prevent directories from being repopulated too. */
506 #define KFSCACHE_LOOKUP_F_NO_INSERT KU32_C(1)
507 /** No refreshing cache entries. */
508 #define KFSCACHE_LOOKUP_F_NO_REFRESH KU32_C(2)
509 /** @} */
467510
468511 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
512 KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere);
513 #ifndef NDEBUG /* enable to debug object release. */
514 # define kFsCacheObjRelease(a_pCache, a_pObj) kFsCacheObjReleaseTagged(a_pCache, a_pObj, __FUNCTION__)
515 #endif
469516 KU32 kFsCacheObjRetain(PKFSOBJ pObj);
470517 PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData);
471518 PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey);
483530 void kFsCacheInvalidateCustomMissing(PKFSCACHE pCache);
484531 void kFsCacheInvalidateCustomBoth(PKFSCACHE pCache);
485532 KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot);
486
487 #endif
533 KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir);
534
535 #endif
0 /* $Id: ntdir.c 2708 2013-11-21 10:26:40Z bird $ */
0 /* $Id: ntdir.c 2985 2016-11-01 18:26:35Z bird $ */
11 /** @file
22 * MSC + NT opendir, readdir, telldir, seekdir, and closedir.
33 */
44
55 /*
6 * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
6 * Copyright (c) 2005-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
77 *
88 * Permission is hereby granted, free of charge, to any person obtaining a
99 * copy of this software and associated documentation files (the "Software"),
3434 #include <stdio.h>
3535 #include <errno.h>
3636 #include <malloc.h>
37 #include <assert.h>
3738
3839 #include "ntstuff.h"
3940 #include "nthlp.h"
4142
4243
4344 /**
45 * Implements opendir.
46 */
47 BirdDir_T *birdDirOpen(const char *pszPath)
48 {
49 HANDLE hDir = birdOpenFile(pszPath,
50 FILE_READ_DATA | SYNCHRONIZE,
51 FILE_ATTRIBUTE_NORMAL,
52 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
53 FILE_OPEN,
54 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
55 OBJ_CASE_INSENSITIVE);
56 if (hDir != INVALID_HANDLE_VALUE)
57 {
58 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE);
59 if (pDir)
60 return pDir;
61 birdCloseFile(hDir);
62 }
63 return NULL;
64 }
65
66
67 /**
68 * Alternative opendir, with extra stat() info returned by readdir().
69 */
70 BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)
71 {
72 HANDLE hDir = birdOpenFile(pszPath,
73 FILE_READ_DATA | SYNCHRONIZE,
74 FILE_ATTRIBUTE_NORMAL,
75 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
76 FILE_OPEN,
77 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
78 OBJ_CASE_INSENSITIVE);
79 if (hDir != INVALID_HANDLE_VALUE)
80 {
81 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE | BIRDDIR_F_EXTRA_INFO);
82 if (pDir)
83 return pDir;
84 birdCloseFile(hDir);
85 }
86 return NULL;
87 }
88
89
90 BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags)
91 {
92 HANDLE hDir = birdOpenFileExW((HANDLE)hRoot,
93 pwszPath,
94 FILE_READ_DATA | SYNCHRONIZE,
95 FILE_ATTRIBUTE_NORMAL,
96 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
97 FILE_OPEN,
98 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
99 OBJ_CASE_INSENSITIVE);
100 if (hDir != INVALID_HANDLE_VALUE)
101 {
102 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, pwszFilter, fFlags | BIRDDIR_F_CLOSE_HANDLE);
103 if (pDir)
104 return pDir;
105 birdCloseFile(hDir);
106 }
107 return NULL;
108 }
109
110
111 /**
44112 * Internal worker for birdStatModTimeOnly.
45113 */
46 static BirdDir_T *birdDirOpenInternal(const char *pszPath, const char *pszFilter, int fMinimalInfo)
47 {
48 HANDLE hFile = birdOpenFile(pszPath,
49 FILE_READ_DATA | SYNCHRONIZE,
50 FILE_ATTRIBUTE_NORMAL,
51 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
52 FILE_OPEN,
53 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
54 OBJ_CASE_INSENSITIVE);
55 if (hFile != INVALID_HANDLE_VALUE)
114 BirdDir_T *birdDirOpenFromHandle(void *pvHandle, const void *pvReserved, unsigned fFlags)
115 {
116 if (!pvReserved)
56117 {
57118 /*
58 * Allocate a handle.
119 * Allocate and initialize the directory enum handle.
59120 */
60121 BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir));
61122 if (pDir)
62123 {
63 pDir->uMagic = BIRD_DIR_MAGIC;
64 pDir->pvHandle = (void *)hFile;
65 pDir->uDev = 0;
66 pDir->offPos = 0;
67 pDir->fHaveData = 0;
68 pDir->fFirst = 1;
69 pDir->iInfoClass = fMinimalInfo ? MyFileNamesInformation : MyFileIdFullDirectoryInformation;
70 pDir->offBuf = 0;
71 pDir->cbBuf = 0;
72 pDir->pabBuf = NULL;
124 pDir->uMagic = BIRD_DIR_MAGIC;
125 pDir->fFlags = fFlags;
126 pDir->pvHandle = pvHandle;
127 pDir->uDev = 0;
128 pDir->offPos = 0;
129 pDir->fHaveData = 0;
130 pDir->fFirst = 1;
131 pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation;
132 pDir->offBuf = 0;
133 pDir->cbBuf = 0;
134 pDir->pabBuf = NULL;
73135 return pDir;
74136 }
75
76 birdCloseFile(hFile);
77 birdSetErrnoToNoMem();
78 }
79
137 }
138 else
139 assert(pvReserved == NULL);
140 birdSetErrnoToNoMem();
80141 return NULL;
81 }
82
83
84 /**
85 * Implements opendir.
86 */
87 BirdDir_T *birdDirOpen(const char *pszPath)
88 {
89 return birdDirOpenInternal(pszPath, NULL, 1 /*fMinimalInfo*/);
90 }
91
92
93 /**
94 * Alternative opendir, with extra stat() info returned by readdir().
95 */
96 BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)
97 {
98 return birdDirOpenInternal(pszPath, NULL, 0 /*fMinimalInfo*/);
99142 }
100143
101144
156199 (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass,
157200 FALSE, /* fReturnSingleEntry */
158201 NULL, /* Filter / restart pos. */
159 FALSE); /* fRestartScan */
202 pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */
160203 if (!MY_NT_SUCCESS(rcNt))
161204 {
162205 int rc;
171214
172215 pDir->offBuf = 0;
173216 pDir->fHaveData = 1;
217 pDir->fFlags &= ~BIRDDIR_F_RESTART_SCAN;
174218
175219 return 0;
176220 }
353397 return birdSetErrnoToBadFileNo();
354398
355399 pDir->uMagic++;
356 birdCloseFile((HANDLE)pDir->pvHandle);
400 if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE)
401 birdCloseFile((HANDLE)pDir->pvHandle);
357402 pDir->pvHandle = (void *)INVALID_HANDLE_VALUE;
358403 birdMemFree(pDir->pabBuf);
359404 pDir->pabBuf = NULL;
0 /* $Id: ntdir.h 2708 2013-11-21 10:26:40Z bird $ */
0 /* $Id: ntdir.h 2985 2016-11-01 18:26:35Z bird $ */
11 /** @file
22 * MSC + NT opendir, readdir, closedir and friends.
33 */
6363 #define DT_WHT 14
6464 /** @} */
6565
66 /** @name BIRDDIR_F_XXX - birdDirOpenFromHandle & BirdDir_T::fFlags
67 * @{ */
68 /** birdDirClose should also close pvHandle. */
69 #define BIRDDIR_F_CLOSE_HANDLE 1U
70 /** birdDirClose should not close the handle. */
71 #define BIRDDIR_F_KEEP_HANDLE 0U
72 /** Provide extra info (stat). */
73 #define BIRDDIR_F_EXTRA_INFO 2U
74 /** Whether to restart the scan. */
75 #define BIRDDIR_F_RESTART_SCAN 4U
76 /** @} */
77
6678 typedef struct BirdDir
6779 {
6880 /** Magic value. */
6981 unsigned uMagic;
82 /** Flags. */
83 unsigned fFlags;
7084 /** The directory handle. */
7185 void *pvHandle;
7286 /** The device number (st_dev). */
96110
97111 BirdDir_T *birdDirOpen(const char *pszPath);
98112 BirdDir_T *birdDirOpenExtraInfo(const char *pszPath);
113 BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags);
114 BirdDir_T *birdDirOpenFromHandle(void *hDir, const void *pvReserved, unsigned fFlags);
99115 BirdDirEntry_T *birdDirRead(BirdDir_T *pDir);
100116 long birdDirTell(BirdDir_T *pDir);
101117 void birdDirSeek(BirdDir_T *pDir, long offDir);
0 /* $Id: nthlp.h 2862 2016-09-02 02:39:56Z bird $ */
0 /* $Id: nthlp.h 2997 2016-11-01 23:28:02Z bird $ */
11 /** @file
22 * MSC + NT helper functions.
33 */
5353 int birdSetErrnoToBadFileNo(void);
5454
5555
56 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
57 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
58 HANDLE birdOpenParentDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
59 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
56 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
57 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
58 HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
59 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
60 HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
61 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
62 HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
63 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
64 HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
65 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
6066 MY_UNICODE_STRING *pNameUniStr);
61 MY_NTSTATUS birdOpenFileUniStr(MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
67 HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
68 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
69 MY_UNICODE_STRING *pNameUniStr);
70 MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
6271 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
6372 HANDLE *phFile);
73 HANDLE birdOpenCurrentDirectory(void);
6474 void birdCloseFile(HANDLE hFile);
6575 int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath);
76 int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath);
6677 void birdFreeNtPath(MY_UNICODE_STRING *pNtPath);
6778
6879
0 /* $Id: nthlpcore.c 2862 2016-09-02 02:39:56Z bird $ */
0 /* $Id: nthlpcore.c 2985 2016-11-01 18:26:35Z bird $ */
11 /** @file
22 * MSC + NT core helpers functions and globals.
33 */
4444 MY_NTSTATUS (WINAPI *g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *,
4545 PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
4646 MY_NTSTATUS (WINAPI *g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *);
47 MY_NTSTATUS (WINAPI *g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet,
48 MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions);
4749 MY_NTSTATUS (WINAPI *g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx,
4850 MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile,
4951 PULONG puKey);
6062 BOOLEAN (WINAPI *g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *, MY_UNICODE_STRING const *, BOOLEAN);
6163 BOOLEAN (WINAPI *g_pfnRtlEqualString)(MY_ANSI_STRING const *, MY_ANSI_STRING const *, BOOLEAN);
6264 UCHAR (WINAPI *g_pfnRtlUpperChar)(UCHAR uch);
65 ULONG (WINAPI *g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt);
66 VOID (WINAPI *g_pfnRtlAcquirePebLock)(VOID);
67 VOID (WINAPI *g_pfnRtlReleasePebLock)(VOID);
6368
6469
6570 static struct
7176 { (FARPROC *)&g_pfnNtClose, "NtClose" },
7277 { (FARPROC *)&g_pfnNtCreateFile, "NtCreateFile" },
7378 { (FARPROC *)&g_pfnNtDeleteFile, "NtDeleteFile" },
79 { (FARPROC *)&g_pfnNtDuplicateObject, "NtDuplicateObject" },
7480 { (FARPROC *)&g_pfnNtReadFile, "NtReadFile" },
7581 { (FARPROC *)&g_pfnNtQueryInformationFile, "NtQueryInformationFile" },
7682 { (FARPROC *)&g_pfnNtQueryVolumeInformationFile, "NtQueryVolumeInformationFile" },
8389 { (FARPROC *)&g_pfnRtlEqualUnicodeString, "RtlEqualUnicodeString" },
8490 { (FARPROC *)&g_pfnRtlEqualString, "RtlEqualString" },
8591 { (FARPROC *)&g_pfnRtlUpperChar, "RtlUpperChar" },
92 { (FARPROC *)&g_pfnRtlNtStatusToDosError, "RtlNtStatusToDosError" },
93 { (FARPROC *)&g_pfnRtlAcquirePebLock, "RtlAcquirePebLock" },
94 { (FARPROC *)&g_pfnRtlReleasePebLock, "RtlReleasePebLock" },
8695 };
8796 /** Set to 1 if we've successfully resolved the imports, otherwise 0. */
8897 int g_fResolvedNtImports = 0;
154163 {
155164 /* EPERM = 1 */
156165 case STATUS_CANNOT_DELETE:
157 case STATUS_DELETE_PENDING:
158166 return EPERM;
159167 /* ENOENT = 2 */
160168 case STATUS_NOT_FOUND:
171179 case STATUS_BAD_NETWORK_PATH:
172180 case STATUS_DFS_EXIT_PATH_FOUND:
173181 case RPC_NT_OBJECT_NOT_FOUND:
182 case STATUS_DELETE_PENDING:
174183 return ENOENT;
175184 /* ESRCH = 3 */
176185 case STATUS_PROCESS_NOT_IN_JOB:
376385 int birdSetErrnoFromNt(MY_NTSTATUS rcNt)
377386 {
378387 errno = birdErrnoFromNtStatus(rcNt);
388 #if 0
389 {
390 ULONG rcWin32;
391 _doserrno = rcWin32 = g_pfnRtlNtStatusToDosError(rcNt);
392 SetLastError(rcWin32);
393 }
394 #endif
379395 return -1;
380396 }
381397
0 /* $Id: nthlpfs.c 2713 2013-11-21 21:11:00Z bird $ */
0 /* $Id: nthlpfs.c 2997 2016-11-01 23:28:02Z bird $ */
11 /** @file
22 * MSC + NT helpers for file system related functions.
33 */
3232 * Header Files *
3333 *******************************************************************************/
3434 #include "nthlp.h"
35 #include <stddef.h>
36 #include <string.h>
37 #include <wchar.h>
38 #include <errno.h>
3539
3640
3741 /*******************************************************************************
5963 }
6064
6165
66 static int birdHasTrailingSlashW(const wchar_t *pwszPath)
67 {
68 wchar_t wc, wc2;
69
70 /* Skip leading slashes. */
71 while ((wc = *pwszPath) == '/' || wc == '\\')
72 pwszPath++;
73 if (wc == '\0')
74 return 0;
75
76 /* Find the last char. */
77 while ((wc2 = *++pwszPath) != '\0')
78 wc = wc2;
79
80 return wc == '/' || wc == '\\' || wc == ':';
81 }
82
83
6284 static int birdIsPathDirSpec(const char *pszPath)
6385 {
6486 char ch, ch2;
7395 ch = ch2;
7496
7597 return ch == '/' || ch == '\\' || ch == ':';
98 }
99
100
101 static int birdIsPathDirSpecW(const wchar_t *pwszPath)
102 {
103 wchar_t wc, wc2;
104
105 /* Check for empty string. */
106 wc = *pwszPath;
107 if (wc == '\0')
108 return 0;
109
110 /* Find the last char. */
111 while ((wc2 = *++pwszPath) != '\0')
112 wc = wc2;
113
114 return wc == '/' || wc == '\\' || wc == ':';
76115 }
77116
78117
117156 }
118157
119158
159 int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath)
160 {
161 birdResolveImports();
162
163 pNtPath->Length = pNtPath->MaximumLength = 0;
164 pNtPath->Buffer = NULL;
165
166 /*
167 * Convert the wide DOS path to an NT path.
168 */
169 if (g_pfnRtlDosPathNameToNtPathName_U(pwszPath, pNtPath, NULL, FALSE))
170 return 0;
171 return birdSetErrnoFromNt(STATUS_NO_MEMORY);
172 }
173
174
175 /**
176 * Converts UNIX slashes to DOS ones.
177 *
178 * @returns 0
179 * @param pNtPath The relative NT path to fix up.
180 */
181 static int birdFixRelativeNtPathSlashesAndReturn0(MY_UNICODE_STRING *pNtPath)
182 {
183 size_t cwcLeft = pNtPath->Length / sizeof(wchar_t);
184 wchar_t *pwcStart = pNtPath->Buffer;
185 wchar_t *pwcHit;
186
187 /* Convert slashes. */
188 while ((pwcHit = wmemchr(pwcStart, '/', cwcLeft)) != NULL)
189 {
190 *pwcHit = '\\';
191 cwcLeft -= pwcHit - pwcStart;
192 pwcHit = pwcStart;
193 }
194
195 #if 0
196 /* Strip trailing slashes (NT doesn't like them). */
197 while ( pNtPath->Length >= sizeof(wchar_t)
198 && pNtPath->Buffer[(pNtPath->Length - sizeof(wchar_t)) / sizeof(wchar_t)] == '\\')
199 {
200 pNtPath->Length -= sizeof(wchar_t);
201 pNtPath->Buffer[pNtPath->Length / sizeof(wchar_t)] = '\0';
202 }
203
204 /* If it was all trailing slashes we convert it to a dot path. */
205 if ( pNtPath->Length == 0
206 && pNtPath->MaximumLength >= sizeof(wchar_t) * 2)
207 {
208 pNtPath->Length = sizeof(wchar_t);
209 pNtPath->Buffer[0] = '.';
210 pNtPath->Buffer[1] = '\0';
211 }
212 #endif
213
214 return 0;
215 }
216
217
218 /**
219 * Similar to birdDosToNtPath, but it does call RtlDosPathNameToNtPathName_U.
220 *
221 * @returns 0 on success, -1 + errno on failure.
222 * @param pszPath The relative path.
223 * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done.
224 */
225 int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath)
226 {
227 MY_NTSTATUS rcNt;
228 MY_ANSI_STRING Src;
229
230 birdResolveImports();
231
232 /*
233 * Just convert to wide char.
234 */
235 pNtPath->Length = pNtPath->MaximumLength = 0;
236 pNtPath->Buffer = NULL;
237
238 Src.Buffer = (PCHAR)pszPath;
239 Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath);
240
241 rcNt = g_pfnRtlAnsiStringToUnicodeString(pNtPath, &Src, TRUE /* Allocate */);
242 if (MY_NT_SUCCESS(rcNt))
243 return birdFixRelativeNtPathSlashesAndReturn0(pNtPath);
244 return birdSetErrnoFromNt(rcNt);
245 }
246
247
248 /**
249 * Similar to birdDosToNtPathW, but it does call RtlDosPathNameToNtPathName_U.
250 *
251 * @returns 0 on success, -1 + errno on failure.
252 * @param pwszPath The relative path.
253 * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done.
254 */
255 int birdDosToRelativeNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath)
256 {
257 size_t cwcPath = wcslen(pwszPath);
258 if (cwcPath < 0xfffe)
259 {
260 pNtPath->Length = (USHORT)(cwcPath * sizeof(wchar_t));
261 pNtPath->MaximumLength = pNtPath->Length + sizeof(wchar_t);
262 pNtPath->Buffer = HeapAlloc(GetProcessHeap(), 0, pNtPath->MaximumLength);
263 if (pNtPath->Buffer)
264 {
265 memcpy(pNtPath->Buffer, pwszPath, pNtPath->MaximumLength);
266 return birdFixRelativeNtPathSlashesAndReturn0(pNtPath);
267 }
268 errno = ENOMEM;
269 }
270 else
271 errno = ENAMETOOLONG;
272 return -1;
273 }
274
275
276 /**
277 * Frees a string returned by birdDosToNtPath, birdDosToNtPathW or
278 * birdDosToRelativeNtPath.
279 *
280 * @param pNtPath The the NT path to free.
281 */
120282 void birdFreeNtPath(MY_UNICODE_STRING *pNtPath)
121283 {
122284 HeapFree(GetProcessHeap(), 0, pNtPath->Buffer);
126288 }
127289
128290
129 MY_NTSTATUS birdOpenFileUniStr(MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
291 MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
130292 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
131293 HANDLE *phFile)
132294 {
142304
143305 Ios.Information = -1;
144306 Ios.u.Status = 0;
145 MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, NULL /*hRoot*/, NULL /*pSecAttr*/);
307 MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, hRoot, NULL /*pSecAttr*/);
146308
147309 rcNt = g_pfnNtCreateFile(phFile,
148310 fDesiredAccess,
183345 }
184346
185347
186 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
187 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
348 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
349 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
188350 {
189351 MY_UNICODE_STRING NtPath;
190352 MY_NTSTATUS rcNt;
196358 fCreateOptions |= FILE_DIRECTORY_FILE;
197359
198360 /*
199 * Call the NT API directly.
361 * Convert the path and call birdOpenFileUniStr to do the real work.
200362 */
201363 if (birdDosToNtPath(pszPath, &NtPath) == 0)
202364 {
203365 HANDLE hFile;
204 rcNt = birdOpenFileUniStr(&NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
366 rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
205367 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
368 birdFreeNtPath(&NtPath);
369 if (MY_NT_SUCCESS(rcNt))
370 return hFile;
371 birdSetErrnoFromNt(rcNt);
372 }
373
374 return INVALID_HANDLE_VALUE;
375 }
376
377
378 HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
379 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
380 {
381 MY_UNICODE_STRING NtPath;
382 MY_NTSTATUS rcNt;
383
384 /*
385 * Adjust inputs.
386 */
387 if (birdIsPathDirSpecW(pwszPath))
388 fCreateOptions |= FILE_DIRECTORY_FILE;
389
390 /*
391 * Convert the path and call birdOpenFileUniStr to do the real work.
392 */
393 if (birdDosToNtPathW(pwszPath, &NtPath) == 0)
394 {
395 HANDLE hFile;
396 rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
397 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
398 birdFreeNtPath(&NtPath);
399 if (MY_NT_SUCCESS(rcNt))
400 return hFile;
401 birdSetErrnoFromNt(rcNt);
402 }
403
404 return INVALID_HANDLE_VALUE;
405 }
406
407
408 HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
409 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
410 {
411 MY_UNICODE_STRING NtPath;
412 MY_NTSTATUS rcNt;
413
414 /*
415 * Adjust inputs.
416 */
417 if (birdIsPathDirSpec(pszPath))
418 fCreateOptions |= FILE_DIRECTORY_FILE;
419
420 /*
421 * Convert the path and call birdOpenFileUniStr to do the real work.
422 */
423 if (hRoot == INVALID_HANDLE_VALUE)
424 hRoot = NULL;
425 if ((hRoot != NULL ? birdDosToRelativeNtPath(pszPath, &NtPath) : birdDosToNtPath(pszPath, &NtPath)) == 0)
426 {
427 HANDLE hFile;
428 rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
429 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
430 birdFreeNtPath(&NtPath);
431 if (MY_NT_SUCCESS(rcNt))
432 return hFile;
433 birdSetErrnoFromNt(rcNt);
434 }
435
436 return INVALID_HANDLE_VALUE;
437 }
438
439
440 HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
441 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
442 {
443 MY_UNICODE_STRING NtPath;
444 MY_NTSTATUS rcNt;
445
446 /*
447 * Adjust inputs.
448 */
449 if (birdIsPathDirSpecW(pwszPath))
450 fCreateOptions |= FILE_DIRECTORY_FILE;
451
452 /*
453 * Convert the path (could save ourselves this if pwszPath is perfect) and
454 * call birdOpenFileUniStr to do the real work.
455 */
456 if (hRoot == INVALID_HANDLE_VALUE)
457 hRoot = NULL;
458 if ((hRoot != NULL ? birdDosToRelativeNtPathW(pwszPath, &NtPath) : birdDosToNtPathW(pwszPath, &NtPath)) == 0)
459 {
460 HANDLE hFile;
461 rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
462 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
463 birdFreeNtPath(&NtPath);
464 if (MY_NT_SUCCESS(rcNt))
465 return hFile;
466 birdSetErrnoFromNt(rcNt);
467 }
468
469 return INVALID_HANDLE_VALUE;
470 }
471
472
473 static HANDLE birdOpenParentDirCommon(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
474 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
475 MY_UNICODE_STRING *pNameUniStr)
476 {
477 MY_NTSTATUS rcNt;
478
479 /*
480 * Strip the path down to the directory.
481 */
482 USHORT offName = pNtPath->Length / sizeof(WCHAR);
483 USHORT cwcName = offName;
484 WCHAR wc = 0;
485 while ( offName > 0
486 && (wc = pNtPath->Buffer[offName - 1]) != '\\'
487 && wc != '/'
488 && wc != ':')
489 offName--;
490 if ( offName > 0
491 || (hRoot != NULL && cwcName > 0))
492 {
493 cwcName -= offName;
494
495 /* Make a copy of the file name, if requested. */
496 rcNt = STATUS_SUCCESS;
497 if (pNameUniStr)
498 {
499 pNameUniStr->Length = cwcName * sizeof(WCHAR);
500 pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR);
501 pNameUniStr->Buffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength);
502 if (pNameUniStr->Buffer)
503 {
504 memcpy(pNameUniStr->Buffer, &pNtPath->Buffer[offName], pNameUniStr->Length);
505 pNameUniStr->Buffer[cwcName] = '\0';
506 }
507 else
508 rcNt = STATUS_NO_MEMORY;
509 }
510
511 /* Chop, chop. */
512 // Bad idea, breaks \\?\c:\pagefile.sys. //while ( offName > 0
513 // Bad idea, breaks \\?\c:\pagefile.sys. // && ( (wc = pNtPath->Buffer[offName - 1]) == '\\'
514 // Bad idea, breaks \\?\c:\pagefile.sys. // || wc == '/'))
515 // Bad idea, breaks \\?\c:\pagefile.sys. // offName--;
516 if (offName == 0)
517 pNtPath->Buffer[offName++] = '.'; /* Hack for dir handle + dir entry name. */
518 pNtPath->Length = offName * sizeof(WCHAR);
519 pNtPath->Buffer[offName] = '\0';
206520 if (MY_NT_SUCCESS(rcNt))
207521 {
208 birdFreeNtPath(&NtPath);
209 return hFile;
210 }
211
212 birdFreeNtPath(&NtPath);
213 birdSetErrnoFromNt(rcNt);
214 }
215
216 return INVALID_HANDLE_VALUE;
217 }
218
219
220 HANDLE birdOpenParentDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
221 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
222 MY_UNICODE_STRING *pNameUniStr)
223 {
224 MY_UNICODE_STRING NtPath;
225 MY_NTSTATUS rcNt;
226
227 /*
228 * Adjust inputs.
229 */
230 fCreateOptions |= FILE_DIRECTORY_FILE;
231
232 /*
233 * Convert the path and split off the filename.
234 */
235 if (birdDosToNtPath(pszPath, &NtPath) == 0)
236 {
237 USHORT offName = NtPath.Length / sizeof(WCHAR);
238 USHORT cwcName = offName;
239 WCHAR wc = 0;
240
241 while ( offName > 0
242 && (wc = NtPath.Buffer[offName - 1]) != '\\'
243 && wc != '/'
244 && wc != ':')
245 offName--;
246 if (offName > 0)
247 {
248 cwcName -= offName;
249
250 /* Make a copy of the file name, if requested. */
251 rcNt = STATUS_SUCCESS;
252 if (pNameUniStr)
253 {
254 pNameUniStr->Length = cwcName * sizeof(WCHAR);
255 pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR);
256 pNameUniStr->Buffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength);
257 if (pNameUniStr->Buffer)
258 {
259 memcpy(pNameUniStr->Buffer, &NtPath.Buffer[offName],pNameUniStr->Length);
260 pNameUniStr->Buffer[cwcName] = '\0';
261 }
262 else
263 rcNt = STATUS_NO_MEMORY;
264 }
265
266 /* Chop, chop. */
267 // Bad idea, breaks \\?\c:\pagefile.sys. //while ( offName > 0
268 // Bad idea, breaks \\?\c:\pagefile.sys. // && ( (wc = NtPath.Buffer[offName - 1]) == '\\'
269 // Bad idea, breaks \\?\c:\pagefile.sys. // || wc == '/'))
270 // Bad idea, breaks \\?\c:\pagefile.sys. // offName--;
271 NtPath.Length = offName * sizeof(WCHAR);
272 NtPath.Buffer[offName] = '\0';
522 /*
523 * Finally, try open the directory.
524 */
525 HANDLE hFile;
526 fCreateOptions |= FILE_DIRECTORY_FILE;
527 rcNt = birdOpenFileUniStr(hRoot, pNtPath, fDesiredAccess, fFileAttribs, fShareAccess,
528 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
273529 if (MY_NT_SUCCESS(rcNt))
274530 {
275 /*
276 * Finally, try open the directory.
277 */
278 HANDLE hFile;
279 rcNt = birdOpenFileUniStr(&NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
280 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile);
281 if (MY_NT_SUCCESS(rcNt))
282 {
283 birdFreeNtPath(&NtPath);
284 return hFile;
285 }
531 birdFreeNtPath(pNtPath);
532 return hFile;
286533 }
287
288 if (pNameUniStr)
289 birdFreeNtPath(pNameUniStr);
290534 }
291535
292 birdFreeNtPath(&NtPath);
293 birdSetErrnoFromNt(rcNt);
294 }
295
536 if (pNameUniStr)
537 birdFreeNtPath(pNameUniStr);
538 }
539 else
540 rcNt = STATUS_INVALID_PARAMETER;
541
542 birdFreeNtPath(pNtPath);
543 birdSetErrnoFromNt(rcNt);
296544 return INVALID_HANDLE_VALUE;
545 }
546
547
548 HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
549 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
550 MY_UNICODE_STRING *pNameUniStr)
551 {
552 /*
553 * Convert the path and join up with the UTF-16 version (it'll free NtPath).
554 */
555 MY_UNICODE_STRING NtPath;
556 if (hRoot == INVALID_HANDLE_VALUE)
557 hRoot = NULL;
558 if ( hRoot == NULL
559 ? birdDosToNtPath(pszPath, &NtPath) == 0
560 : birdDosToRelativeNtPath(pszPath, &NtPath) == 0)
561 return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
562 fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr);
563 return INVALID_HANDLE_VALUE;
564 }
565
566
567 HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,
568 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
569 MY_UNICODE_STRING *pNameUniStr)
570 {
571 /*
572 * Convert the path and join up with the ansi version (it'll free NtPath).
573 */
574 MY_UNICODE_STRING NtPath;
575 if (hRoot == INVALID_HANDLE_VALUE)
576 hRoot = NULL;
577 if ( hRoot == NULL
578 ? birdDosToNtPathW(pwszPath, &NtPath) == 0
579 : birdDosToRelativeNtPathW(pwszPath, &NtPath) == 0)
580 return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,
581 fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr);
582 return INVALID_HANDLE_VALUE;
583 }
584
585
586 /**
587 * Returns a handle to the current working directory of the process.
588 *
589 * @returns CWD handle with FILE_TRAVERSE and SYNCHRONIZE access. May return
590 * INVALID_HANDLE_VALUE w/ errno for invalid CWD.
591 */
592 HANDLE birdOpenCurrentDirectory(void)
593 {
594 PMY_RTL_USER_PROCESS_PARAMETERS pProcParams;
595 MY_NTSTATUS rcNt;
596 HANDLE hRet = INVALID_HANDLE_VALUE;
597
598 birdResolveImports();
599
600 /*
601 * We'll try get this from the PEB.
602 */
603 g_pfnRtlAcquirePebLock();
604 pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)MY_NT_CURRENT_PEB()->ProcessParameters;
605 if (pProcParams != NULL)
606 rcNt = g_pfnNtDuplicateObject(MY_NT_CURRENT_PROCESS, pProcParams->CurrentDirectory.Handle,
607 MY_NT_CURRENT_PROCESS, &hRet,
608 FILE_TRAVERSE | SYNCHRONIZE,
609 0 /*fAttribs*/,
610 0 /*fOptions*/);
611 else
612 rcNt = STATUS_INVALID_PARAMETER;
613 g_pfnRtlReleasePebLock();
614 if (MY_NT_SUCCESS(rcNt))
615 return hRet;
616
617 /*
618 * Fallback goes thru birdOpenFileW.
619 */
620 return birdOpenFileW(L".",
621 FILE_TRAVERSE | SYNCHRONIZE,
622 FILE_ATTRIBUTE_NORMAL,
623 FILE_SHARE_READ | FILE_SHARE_WRITE,
624 FILE_OPEN,
625 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
626 OBJ_CASE_INSENSITIVE);
297627 }
298628
299629
0 /* $Id: ntstat.c 2880 2016-09-05 20:36:26Z bird $ */
0 /* $Id: ntstat.c 2993 2016-11-01 22:41:26Z bird $ */
11 /** @file
22 * MSC + NT stat, lstat and fstat.
33 */
4444
4545 static int birdIsExecutableExtension(const char *pszExt)
4646 {
47 return !strcmp(pszExt, "exe")
48 || !strcmp(pszExt, "cmd")
49 || !strcmp(pszExt, "bat")
50 || !strcmp(pszExt, "vbs")
51 || !strcmp(pszExt, "com")
52 ;
47 switch (pszExt[0])
48 {
49 default:
50 return 0;
51
52 case 'e': /* exe */
53 return pszExt[1] == 'x' && pszExt[2] == 'e' && pszExt[3] == '\0';
54
55 case 'b': /* bat */
56 return pszExt[1] == 'a' && pszExt[2] == 't' && pszExt[3] == '\0';
57
58 case 'v': /* vbs */
59 return pszExt[1] == 'v' && pszExt[2] == 's' && pszExt[3] == '\0';
60
61 case 'c': /* com and cmd */
62 return (pszExt[1] == 'o' && pszExt[2] == 'm' && pszExt[3] == '\0')
63 || (pszExt[1] == 'm' && pszExt[2] == 'd' && pszExt[3] == '\0');
64 }
5365 }
5466
5567
7789 if (cchExt != 3)
7890 return 0;
7991
80 /* Copy the extension out and lower case it. */
92 /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */
8193 for (i = 0; i < cchExt; i++, pszExt++)
8294 {
8395 ch = *pszExt;
84 if (ch >= 'A' && ch <= 'Z')
96 if (ch >= 'a' && ch <= 'z')
97 { /* likely */ }
98 else if (ch >= 'A' && ch <= 'Z')
8599 ch += 'a' - 'A';
100 else
101 return 0;
86102 szExt[i] = ch;
87103 }
88104 szExt[i] = '\0';
91107 }
92108
93109
94 static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName)
110 /**
111 * @a pwcName could be the full path.
112 */
113 static int birdIsFileExecutableW(WCHAR const *pwcName, size_t cwcName)
95114 {
96115 char szExt[8];
97116 unsigned cchExt;
108127 else
109128 return 0;
110129
111 /* Copy the extension out and lower case it. */
130 /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */
112131 pwc = &pwcName[cwcName - cchExt];
113132 for (i = 0; i < cchExt; i++, pwc++)
114133 {
115134 WCHAR wc = *pwc;
116 if (wc >= 'A' && wc <= 'Z')
135 if (wc >= 'a' && wc <= 'z')
136 { /* likely */ }
137 else if (wc >= 'A' && wc <= 'Z')
117138 wc += 'a' - 'A';
118 else if (wc > 255)
119 wc = 255;
139 else
140 return 0;
120141 szExt[i] = (char)wc;
121142 }
122143 szExt[i] = '\0';
126147
127148
128149 static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName,
129 MY_FILE_NAME_INFORMATION *pNameInfo, __int16 *pfIsDirSymlink)
150 const wchar_t *pwszName, size_t cbNameW, __int16 *pfIsDirSymlink)
130151 {
131152 unsigned short fMode;
132153
165186 if (!(fAttribs & FILE_ATTRIBUTE_READONLY))
166187 fMode |= S_IWOTH | S_IWGRP | S_IWUSR;
167188 if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
168 || (pszName
169 ? birdIsFileExecutable(pszName)
170 : birdIsFileExecutableW(pNameInfo->FileName, pNameInfo->FileNameLength)) )
189 || (pwszName
190 ? birdIsFileExecutableW(pwszName, cbNameW)
191 : birdIsFileExecutable(pszName)) )
171192 fMode |= S_IXOTH | S_IXGRP | S_IXUSR;
172193
173194 return fMode;
184205 */
185206 void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
186207 {
187 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
188 NULL, &pStat->st_dirsymlink);
208 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
209 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
189210 pStat->st_padding0[0] = 0;
190211 pStat->st_padding0[1] = 0;
191212 pStat->st_size = pBuf->EndOfFile.QuadPart;
216237 */
217238 void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
218239 {
219 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
220 NULL, &pStat->st_dirsymlink);
240 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
241 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
221242 pStat->st_padding0[0] = 0;
222243 pStat->st_padding0[1] = 0;
223244 pStat->st_size = pBuf->EndOfFile.QuadPart;
248269 */
249270 void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
250271 {
251 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
252 NULL, &pStat->st_dirsymlink);
272 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
273 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
253274 pStat->st_padding0[0] = 0;
254275 pStat->st_padding0[1] = 0;
255276 pStat->st_size = pBuf->EndOfFile.QuadPart;
270291 }
271292
272293
273 int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
294 int birdStatHandle2(HANDLE hFile, BirdStat_T *pStat, const char *pszPath, const wchar_t *pwszPath)
274295 {
275296 int rc;
276297 MY_NTSTATUS rcNt;
288309 if (MY_NT_SUCCESS(rcNt))
289310 {
290311 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
291 &pAll->NameInformation, &pStat->st_dirsymlink);
312 pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength,
313 &pStat->st_dirsymlink);
292314 pStat->st_padding0[0] = 0;
293315 pStat->st_padding0[1] = 0;
294316 pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart;
350372 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
351373 if (MY_NT_SUCCESS(rcNt))
352374 rcNt = Ios.u.Status;
353 if (MY_NT_SUCCESS(rcNt) && !pszPath)
375 if (MY_NT_SUCCESS(rcNt) && !pszPath && !pwszPath)
354376 {
355377 cbNameInfo = 0x10020;
356378 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
362384 if (MY_NT_SUCCESS(rcNt))
363385 {
364386 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
365 pNameInfo, &pStat->st_dirsymlink);
387 pNameInfo ? pNameInfo->FileName : pwszPath,
388 pNameInfo ? pNameInfo->FileNameLength
389 : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0,
390 &pStat->st_dirsymlink);
366391 pStat->st_padding0[0] = 0;
367392 pStat->st_padding0[1] = 0;
368393 pStat->st_size = StdInfo.EndOfFile.QuadPart;
411436 }
412437
413438
439 int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
440 {
441 return birdStatHandle2(hFile, pStat, pszPath, NULL);
442 }
443
444
414445 /**
415446 * Generates a device number from the volume information.
416447 *
458489 }
459490
460491
461 static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
492 static int birdStatInternal(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollow)
462493 {
463494 int rc;
464 HANDLE hFile = birdOpenFile(pszPath,
465 FILE_READ_ATTRIBUTES,
466 FILE_ATTRIBUTE_NORMAL,
467 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
468 FILE_OPEN,
469 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
470 OBJ_CASE_INSENSITIVE);
495 HANDLE hFile = birdOpenFileEx(hRoot, pszPath,
496 FILE_READ_ATTRIBUTES,
497 FILE_ATTRIBUTE_NORMAL,
498 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
499 FILE_OPEN,
500 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
501 OBJ_CASE_INSENSITIVE);
471502 if (hFile != INVALID_HANDLE_VALUE)
472503 {
473 rc = birdStatHandle(hFile, pStat, pszPath);
504 rc = birdStatHandle2(hFile, pStat, pszPath, NULL);
474505 birdCloseFile(hFile);
475506
476507 #if 0
498529 && strchr(pszPath, '?') == NULL)
499530 {
500531 MY_UNICODE_STRING NameUniStr;
501 hFile = birdOpenParentDir(pszPath,
532 hFile = birdOpenParentDir(hRoot, pszPath,
502533 FILE_READ_DATA | SYNCHRONIZE,
503534 FILE_ATTRIBUTE_NORMAL,
504535 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
550581 }
551582
552583
584 static int birdStatInternalW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollow)
585 {
586 int rc;
587 HANDLE hFile = birdOpenFileExW(hRoot, pwszPath,
588 FILE_READ_ATTRIBUTES,
589 FILE_ATTRIBUTE_NORMAL,
590 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
591 FILE_OPEN,
592 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
593 OBJ_CASE_INSENSITIVE);
594 if (hFile != INVALID_HANDLE_VALUE)
595 {
596 rc = birdStatHandle2(hFile, pStat, NULL, pwszPath);
597 birdCloseFile(hFile);
598 }
599 else
600 {
601 /*
602 * On things like pagefile.sys we may get sharing violation. We fall
603 * back on directory enumeration for dealing with that.
604 */
605 if ( errno == ETXTBSY
606 && wcschr(pwszPath, '*') == NULL /* Serious paranoia... */
607 && wcschr(pwszPath, '?') == NULL)
608 {
609 MY_UNICODE_STRING NameUniStr;
610 hFile = birdOpenParentDirW(hRoot, pwszPath,
611 FILE_READ_DATA | SYNCHRONIZE,
612 FILE_ATTRIBUTE_NORMAL,
613 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
614 FILE_OPEN,
615 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
616 OBJ_CASE_INSENSITIVE,
617 &NameUniStr);
618 if (hFile != INVALID_HANDLE_VALUE)
619 {
620 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
621 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
622 MY_IO_STATUS_BLOCK Ios;
623 MY_NTSTATUS rcNt;
624
625 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
626 Ios.u.Status = -1;
627 Ios.Information = -1;
628 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
629 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
630 if (MY_NT_SUCCESS(rcNt))
631 rcNt = Ios.u.Status;
632 if (MY_NT_SUCCESS(rcNt))
633 {
634 /*
635 * Convert the data.
636 */
637 birdStatFillFromFileIdFullDirInfo(pStat, pBuf, NULL);
638
639 /* Get the serial number, reusing the buffer from above. */
640 rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev);
641 if (MY_NT_SUCCESS(rcNt))
642 rc = 0;
643 else
644 rc = birdSetErrnoFromNt(rcNt);
645 }
646
647 birdFreeNtPath(&NameUniStr);
648 birdCloseFile(hFile);
649
650 if (MY_NT_SUCCESS(rcNt))
651 return 0;
652 birdSetErrnoFromNt(rcNt);
653 }
654 }
655 rc = -1;
656 }
657
658 return rc;
659 }
660
661
553662 /**
554663 * Implements UNIX fstat().
555664 */
568677 switch (fFileType)
569678 {
570679 case FILE_TYPE_DISK:
571 rc = birdStatHandle(hFile, pStat, NULL);
680 rc = birdStatHandle2(hFile, pStat, NULL, NULL);
572681 break;
573682
574683 case FILE_TYPE_CHAR:
655764 */
656765 int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
657766 {
658 return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
767 return birdStatInternal(NULL, pszPath, pStat, 1 /*fFollow*/);
768 }
769
770
771 /**
772 * Implements UNIX stat().
773 */
774 int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat)
775 {
776 return birdStatInternalW(NULL, pwszPath, pStat, 1 /*fFollow*/);
659777 }
660778
661779
664782 */
665783 int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
666784 {
667 return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
785 return birdStatInternal(NULL, pszPath, pStat, 0 /*fFollow*/);
786 }
787
788
789 /**
790 * Implements UNIX lstat().
791 */
792 int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat)
793 {
794 return birdStatInternalW(NULL, pwszPath, pStat, 0 /*fFollow*/);
795 }
796
797
798 /**
799 * Implements an API like UNIX fstatat().
800 *
801 * @returns 0 on success, -1 and errno on failure.
802 * @param hRoot NT handle pwszPath is relative to.
803 * @param pszPath The path.
804 * @param pStat Where to return stats.
805 * @param fFollowLink Whether to follow links.
806 */
807 int birdStatAt(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink)
808 {
809 return birdStatInternal(hRoot, pszPath, pStat, fFollowLink != 0);
810 }
811
812
813 /**
814 * Implements an API like UNIX fstatat().
815 *
816 * @returns 0 on success, -1 and errno on failure.
817 * @param hRoot NT handle pwszPath is relative to.
818 * @param pwszPath The path.
819 * @param pStat Where to return stats.
820 * @param fFollowLink Whether to follow links.
821 */
822 int birdStatAtW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink)
823 {
824 return birdStatInternalW(hRoot, pwszPath, pStat, fFollowLink != 0);
668825 }
669826
670827
0 /* $Id: ntstat.h 2858 2016-09-01 15:12:24Z bird $ */
0 /* $Id: ntstat.h 2985 2016-11-01 18:26:35Z bird $ */
11 /** @file
22 * MSC + NT stat, lstat and fstat implementation and wrappers.
33 */
7575 #define st_birthtime st_birthtim.tv_sec
7676
7777 int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat);
78 int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat);
7879 int birdStatOnLink(const char *pszPath, BirdStat_T *pStat);
80 int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat);
81 int birdStatAt(void *hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink);
82 int birdStatAtW(void *hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink);
7983 int birdStatOnFd(int fd, BirdStat_T *pStat);
8084 int birdStatOnFdJustSize(int fd, __int64 *pcbFile);
8185 int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink);
0 /* $Id: ntstuff.h 2900 2016-09-09 14:42:06Z bird $ */
0 /* $Id: ntstuff.h 2985 2016-11-01 18:26:35Z bird $ */
11 /** @file
22 * Definitions, types, prototypes and globals for NT.
33 */
3838 #undef WIN32_NO_STATUS
3939 #include <ntstatus.h>
4040 #undef timeval
41
42 #include <k/kTypes.h>
4143
4244
4345 /** @defgroup grp_nt_ntstuff NT Stuff
465467 # define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000U
466468 #endif
467469
470 #ifndef DUPLICATE_CLOSE_SOURCE /* For the misnomer NtDuplicateObject. */
471 # define DUPLICATE_CLOSE_SOURCE 0x00000001U
472 # define DUPLICATE_SAME_ACCESS 0x00000002U
473 #endif
474 #ifndef DUPLICATE_SAME_ATTRIBUTES
475 # define DUPLICATE_SAME_ATTRIBUTES 0x00000004U
476 #endif
477
468478
469479 /** @name NT status codes and associated macros.
470480 * @{ */
478488 #define MY_STATUS_OBJECT_PATH_SYNTAX_BAD ((MY_NTSTATUS)0xc000003b)
479489 /** @} */
480490
491 /** The pseudohandle for the current process. */
492 #define MY_NT_CURRENT_PROCESS ((HANDLE)~(uintptr_t)0)
493 /** The pseudohandle for the current thread. */
494 #define MY_NT_CURRENT_THREAD ((HANDLE)~(uintptr_t)1)
495
496 typedef struct MY_CLIENT_ID
497 {
498 HANDLE UniqueProcess;
499 HANDLE UniqueThread;
500 } MY_CLIENT_ID;
501
502 /** Partial TEB. */
503 typedef struct MY_PARTIAL_TEB
504 {
505 NT_TIB NtTib;
506 PVOID EnvironmentPointer;
507 MY_CLIENT_ID ClientId;
508 PVOID ActiveRpcHandle;
509 PVOID ThreadLocalStoragePointer;
510 PPEB ProcessEnvironmentBlock;
511 KU32 LastErrorValue;
512 KU32 CountOfOwnedCriticalSections;
513 PVOID CsrClientThread;
514 PVOID Win32ThreadInfo;
515 } MY_PARTIAL_TEB;
516
517 /** Internal macro for reading uintptr_t sized TEB members. */
518 #if K_ARCH == K_ARCH_AMD64
519 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readgsqword(a_offTebMember) )
520 #elif K_ARCH == K_ARCH_X86
521 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readfsdword(a_offTebMember) )
522 #else
523 # else "Port me!"
524 #endif
525 /** Get the PEB pointer.
526 * @remark Needs stddef.h. */
527 #define MY_NT_CURRENT_PEB() ( (PPEB)MY_NT_READ_TEB_WORKER(offsetof(MY_PARTIAL_TEB, ProcessEnvironmentBlock)) )
528 /** Get the TEB pointer.
529 * @remark Needs stddef.h. */
530 #define MY_NT_CURRENT_TEB() ( (PTEB)MY_NT_READ_TEB_WORKER(offsetof(NT_TIB, Self)) )
531
481532
482533 /*******************************************************************************
483534 * Global Variables *
486537 extern MY_NTSTATUS (WINAPI * g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *,
487538 PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
488539 extern MY_NTSTATUS (WINAPI * g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *);
540 extern MY_NTSTATUS (WINAPI * g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet,
541 MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions);
489542 extern MY_NTSTATUS (WINAPI * g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx,
490543 MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile,
491544 PULONG puKey);
506559 extern BOOLEAN (WINAPI * g_pfnRtlEqualString)(MY_ANSI_STRING const *pAnsiStr1, MY_ANSI_STRING const *pAnsiStr2,
507560 BOOLEAN fCaseInsensitive);
508561 extern UCHAR (WINAPI * g_pfnRtlUpperChar)(UCHAR uch);
562 extern ULONG (WINAPI * g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt);
563 extern VOID (WINAPI * g_pfnRtlAcquirePebLock)(VOID);
564 extern VOID (WINAPI * g_pfnRtlReleasePebLock)(VOID);
509565
510566
511567 /** @} */
0 /* $Id: ntunlink.c 2713 2013-11-21 21:11:00Z bird $ */
0 /* $Id: ntunlink.c 2997 2016-11-01 23:28:02Z bird $ */
11 /** @file
22 * MSC + NT unlink and variations.
33 */
4444 MY_NTSTATUS rcNt;
4545 HANDLE hFile;
4646
47 rcNt = birdOpenFileUniStr(pNtPath,
47 rcNt = birdOpenFileUniStr(NULL /*hRoot*/,
48 pNtPath,
4849 FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
4950 FILE_ATTRIBUTE_NORMAL,
5051 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
8081 }
8182
8283
83 static int birdUnlinkInternal(const char *pszFile, int fReadOnlyToo, int fFast)
84 static int birdUnlinkInternal(HANDLE hRoot, const char *pszFile, int fReadOnlyToo, int fFast)
8485 {
8586 MY_UNICODE_STRING NtPath;
8687 int rc;
8788
88 rc = birdDosToNtPath(pszFile, &NtPath);
89 if (hRoot == INVALID_HANDLE_VALUE)
90 hRoot = NULL;
91 if (hRoot == NULL)
92 rc = birdDosToNtPath(pszFile, &NtPath);
93 else
94 rc = birdDosToRelativeNtPath(pszFile, &NtPath);
8995 if (rc == 0)
9096 {
9197 MY_NTSTATUS rcNt;
9399 {
94100 /* This uses FILE_DELETE_ON_CLOSE. Probably only suitable when in a hurry... */
95101 MY_OBJECT_ATTRIBUTES ObjAttr;
96 MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, NULL /*hRoot*/, NULL /*pSecAttr*/);
102 MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, hRoot, NULL /*pSecAttr*/);
97103 rcNt = g_pfnNtDeleteFile(&ObjAttr);
98104
99105 /* In case some file system does things differently than NTFS. */
110116 int fMayTryAgain = 1;
111117 for (;;)
112118 {
113 rcNt = birdOpenFileUniStr(&NtPath,
119 rcNt = birdOpenFileUniStr(hRoot,
120 &NtPath,
114121 DELETE,
115122 FILE_ATTRIBUTE_NORMAL,
116123 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
153160
154161 int birdUnlink(const char *pszFile)
155162 {
156 return birdUnlinkInternal(pszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/);
163 return birdUnlinkInternal(NULL /*hRoot*/, pszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/);
164 }
165
166
167 int birdUnlinkEx(void *hRoot, const char *pszFile)
168 {
169 return birdUnlinkInternal((HANDLE)hRoot, pszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/);
157170 }
158171
159172
160173 int birdUnlinkForced(const char *pszFile)
161174 {
162 return birdUnlinkInternal(pszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/);
175 return birdUnlinkInternal(NULL /*hRoot*/, pszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/);
176 }
177
178
179 int birdUnlinkForcedEx(void *hRoot, const char *pszFile)
180 {
181 return birdUnlinkInternal((HANDLE)hRoot, pszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/);
163182 }
164183
165184
166185 int birdUnlinkForcedFast(const char *pszFile)
167186 {
168 return birdUnlinkInternal(pszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/);
187 return birdUnlinkInternal(NULL /*hRoot*/, pszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/);
169188 }
170189
190
191 int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile)
192 {
193 return birdUnlinkInternal((HANDLE)hRoot, pszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/);
194 }
195
0 /* $Id: ntunlink.h 2713 2013-11-21 21:11:00Z bird $ */
0 /* $Id: ntunlink.h 2997 2016-11-01 23:28:02Z bird $ */
11 /** @file
22 * MSC + NT unlink and variations.
33 */
3333 #include "nttypes.h"
3434
3535 int birdUnlink(const char *pszFile);
36 int birdUnlinkEx(void *hRoot, const char *pszFile);
3637 int birdUnlinkForced(const char *pszFile);
38 int birdUnlinkForcedEx(void *hRoot, const char *pszFile);
3739 int birdUnlinkForcedFast(const char *pszFile);
40 int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile);
3841
3942 #undef unlink
4043 #define unlink(a_pszPath) birdUnlinkForced(a_pszPath)
0
1
2 /*********************************************************************************************************************************
3 * Header Files *
4 *********************************************************************************************************************************/
5 #ifndef USE_OLD_FTS
6 # include "fts-nt.h"
7 #else
8 # include "kmkbuiltin/ftsfake.h"
9 #endif
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <errno.h>
14
15
16 static int usage(const char *argv0)
17 {
18 printf("usage: %s [options] <dirs & files>\n", argv0);
19 printf("\n"
20 "options:\n"
21 " -d, --see-dot\n"
22 " FTS_SEEDOT\n"
23 " -p, --physical\n"
24 " FTS_PHYSICAL\n"
25 " -l, --logical\n"
26 " FTS_LOGICAL\n"
27 " -H, --dereference-command-line\n"
28 " FTS_COMFOLLOW\n"
29 " -L, --dereference\n"
30 " Follow symbolic links while scanning directories.\n"
31 " -P, --no-dereference\n"
32 " Do not follow symbolic links while scanning directories.\n"
33 " -c, --no-chdir\n"
34 " FTS_NOCHDIR\n"
35 " -s, --no-stat\n"
36 " FTS_NOSTAT\n"
37 " -x, --one-file-system\n"
38 " FTS_XDEV\n"
39 " -q, --quiet\n"
40 " Quiet operation, no output.\n"
41 " -v, --verbose\n"
42 " Verbose operation (default).\n"
43 );
44 return 0;
45 }
46
47
48 int main(int argc, char **argv)
49 {
50 FTS *pFts;
51 int i;
52 int rcExit = 0;
53 int cVerbosity = 1;
54 int fFollowLinks = 0;
55 int fFtsFlags = 0;
56 unsigned fDoneOptions = 0;
57 unsigned cFtsArgs = 0;
58 char const **papszFtsArgs = calloc(argc + 1, sizeof(char *));
59
60 /*
61 * Parse options and heap up non-options.
62 */
63 for (i = 1; i < argc; i++)
64 {
65 const char *pszArg = argv[i];
66 if (*pszArg == '-' && !fDoneOptions)
67 {
68 char chOpt = *++pszArg;
69 pszArg++;
70 if (chOpt == '-')
71 {
72 chOpt = *pszArg++;
73 if (!chOpt)
74 {
75 fDoneOptions = 1;
76 continue;
77 }
78 if (strcmp(pszArg, "help") == 0)
79 chOpt = 'h';
80 else if (strcmp(pszArg, "version") == 0)
81 chOpt = 'V';
82 else if (strcmp(pszArg, "see-dot") == 0)
83 chOpt = 'd';
84 else if (strcmp(pszArg, "physical") == 0)
85 chOpt = 'p';
86 else if (strcmp(pszArg, "logical") == 0)
87 chOpt = 'l';
88 else if (strcmp(pszArg, "dereference-command-line") == 0)
89 chOpt = 'H';
90 else if (strcmp(pszArg, "no-chdir") == 0)
91 chOpt = 'c';
92 else if (strcmp(pszArg, "no-stat") == 0)
93 chOpt = 's';
94 else if (strcmp(pszArg, "one-file-system") == 0)
95 chOpt = 'x';
96 else if (strcmp(pszArg, "quiet") == 0)
97 chOpt = 'q';
98 else if (strcmp(pszArg, "verbose") == 0)
99 chOpt = 'v';
100 else
101 {
102 fprintf(stderr, "syntax error: Unknown option: --%s\n", pszArg);
103 return 2;
104 }
105 pszArg = "";
106 }
107 do
108 {
109 switch (chOpt)
110 {
111 case '?':
112 case 'h':
113 return usage(argv[0]);
114 case 'V':
115 printf("v0.0.0\n");
116 return 0;
117
118 case 'd':
119 fFtsFlags |= FTS_SEEDOT;
120 break;
121 case 'l':
122 fFtsFlags |= FTS_LOGICAL;
123 break;
124 case 'p':
125 fFtsFlags |= FTS_PHYSICAL;
126 break;
127 case 'H':
128 fFtsFlags |= FTS_COMFOLLOW;
129 break;
130 case 'c':
131 fFtsFlags |= FTS_NOCHDIR;
132 break;
133 case 's':
134 fFtsFlags |= FTS_NOSTAT;
135 break;
136 case 'x':
137 fFtsFlags |= FTS_XDEV;
138 break;
139 case 'L':
140 fFollowLinks = 1;
141 break;
142 case 'P':
143 fFollowLinks = 0;
144 break;
145
146 case 'q':
147 cVerbosity = 0;
148 break;
149 case 'v':
150 cVerbosity++;
151 break;
152
153 default:
154 fprintf(stderr, "syntax error: Unknown option: -%c (%s)\n", chOpt, argv[i]);
155 return 2;
156 }
157 chOpt = *pszArg++;
158 } while (chOpt != '\0');
159 }
160 else
161 papszFtsArgs[cFtsArgs++] = pszArg;
162 }
163
164 #ifdef USE_OLD_FTS
165 if (papszFtsArgs[0] == NULL)
166 {
167 fprintf(stderr, "Nothing to do\n");
168 return 1;
169 }
170 #endif
171
172 /*
173 * Do the traversal.
174 */
175 errno = 0;
176 pFts = fts_open((char **)papszFtsArgs, fFtsFlags, NULL /*pfnCompare*/);
177 if (pFts)
178 {
179 for (;;)
180 {
181 FTSENT *pFtsEnt = fts_read(pFts);
182 if (pFtsEnt)
183 {
184 const char *pszState;
185 switch (pFtsEnt->fts_info)
186 {
187 case FTS_D: pszState = "D"; break;
188 case FTS_DC: pszState = "DC"; break;
189 case FTS_DEFAULT: pszState = "DEFAULT"; break;
190 case FTS_DNR: pszState = "DNR"; break;
191 case FTS_DOT: pszState = "DOT"; break;
192 case FTS_DP: pszState = "DP"; break;
193 case FTS_ERR: pszState = "ERR"; break;
194 case FTS_F: pszState = "F"; break;
195 case FTS_INIT: pszState = "INIT"; break;
196 case FTS_NS: pszState = "NS"; break;
197 case FTS_NSOK: pszState = "NSOK"; break;
198 case FTS_SL: pszState = "SL"; break;
199 case FTS_SLNONE: pszState = "SLNONE"; break;
200 default:
201 pszState = "Invalid";
202 rcExit = 1;
203 break;
204 }
205
206 if (cVerbosity > 0)
207 printf("%8s %s\n", pszState, pFtsEnt->fts_accpath);
208 if ( pFtsEnt->fts_info == FTS_SL
209 && pFtsEnt->fts_number == 0
210 && fFollowLinks
211 && ( (fFtsFlags & FTS_COMFOLLOW)
212 || pFtsEnt->fts_level > FTS_ROOTLEVEL) ) {
213 pFtsEnt->fts_number++;
214 fts_set(pFts, pFtsEnt, FTS_FOLLOW);
215 }
216 }
217 else
218 {
219 if (errno != 0)
220 {
221 fprintf(stderr, "fts_read failed: errno=%d\n", errno);
222 rcExit = 1;
223 }
224 break;
225 }
226 } /* enum loop */
227
228 errno = 0;
229 i = fts_close(pFts);
230 if (i != 0)
231 {
232 fprintf(stderr, "fts_close failed: errno=%d\n", errno);
233 rcExit = 1;
234 }
235 }
236 else
237 {
238 fprintf(stderr, "fts_open failed: errno=%d (cFtsArgs=%u)\n", errno, cFtsArgs);
239 rcExit = 1;
240 }
241
242 return rcExit;
243 }
0 /* $Id: quote_argv.c 2894 2016-09-08 13:27:56Z bird $ */
0 /* $Id: quote_argv.c 2912 2016-09-14 13:36:15Z bird $ */
11 /** @file
22 * quote_argv - Correctly quote argv for spawn, windows specific.
33 */
7878 * For details on how MSC parses the command line, see "Parsing C Command-Line
7979 * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
8080 *
81 * @returns 0 on success, -1 if out of memory.
8182 * @param argc The argument count.
8283 * @param argv The argument vector.
8384 * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar
8889 * depends on which argv you're working on.
8990 * Suggest doing the latter if it's main()'s argv.
9091 */
91 void quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
92 int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
9293 {
9394 int i;
9495 for (i = 0; i < argc; i++)
120121 int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\');
121122 size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2;
122123 char *pszNew = (char *)malloc(cchNew + 1 /*term*/ + 3 /*passthru hack*/);
124 if (!pszNew)
125 return -1;
123126
124127 argv[i] = pszNew;
125128
206209 }
207210
208211 /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/
212 return 0;
209213 }
210214
0 /* $Id: quote_argv.h 2851 2016-08-31 17:30:52Z bird $ */
0 /* $Id: quote_argv.h 2912 2016-09-14 13:36:15Z bird $ */
11 /** @file
22 * quote_argv - Correctly quote argv for spawn, windows specific.
33 */
3232 #define ___quote_argv_h___
3333
3434 #include "mytypes.h"
35 extern void quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak);
35 extern int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak);
3636
3737 #endif
3838