Merge branch 'report-failures' of https://github.com/jacereda/fsatrace into report-failures
diff --git a/Makefile b/Makefile
index c8751f2..072793f 100644
--- a/Makefile
+++ b/Makefile
@@ -49,13 +49,13 @@
 	rm -f fsatrace$(EXE) $(patsubst %.c,%.o,$(SRCS)) $(patsubst %.c,%.d,$(SRCS))
 
 test: all
-	./fsatrace$(EXE) wrmdqt - -- cp /bin/ls /tmp/foo
-	./fsatrace$(EXE) wrmdqt - -- mv /tmp/foo /tmp/bar
-	./fsatrace$(EXE) wrmdqt - -- touch /tmp/bar
-	./fsatrace$(EXE) wrmdqt - -- rm /tmp/bar
-	./fsatrace$(EXE) wrmdqt - -- $(CC) -c -D_GNU_SOURCE -D_BSD_SOURCE=1 -std=c99 -Wall src/fsatrace.c -o /tmp/fsatrace.o
-	./fsatrace$(EXE) wrmdqt - -- sh -c "cp /bin/ls /tmp/foo && mv /tmp/foo /tmp/bar && rm /tmp/bar"
-	./fsatrace$(EXE) wrmdqt! - -- sh -c "cp /bin/ls /tmp/foo && mv /tmp/foo /tmp/bar && rm /tmp/bar" # twice, when dst exists it might use another path
+	./fsatrace$(EXE) ewrmdqt - -- cp /bin/ls /tmp/foo
+	./fsatrace$(EXE) ewrmdqt - -- mv /tmp/foo /tmp/bar
+	./fsatrace$(EXE) ewrmdqt - -- touch /tmp/bar
+	./fsatrace$(EXE) ewrmdqt - -- rm /tmp/bar
+	./fsatrace$(EXE) ewrmdqt - -- $(CC) -c -D_GNU_SOURCE -D_BSD_SOURCE=1 -std=c99 -Wall src/fsatrace.c -o /tmp/fsatrace.o
+	./fsatrace$(EXE) ewrmdqt - -- sh -c "cp /bin/ls /tmp/foo && mv /tmp/foo /tmp/bar && rm /tmp/bar"
+	./fsatrace$(EXE) ewrmdqt! - -- sh -c "cp /bin/ls /tmp/foo && mv /tmp/foo /tmp/bar && rm /tmp/bar" # twice, when dst exists it might use another path
 
 htest: all
 	cd test && stack install && stack test
diff --git a/src/fsatrace.c b/src/fsatrace.c
index d7d51f1..b4fc9e8 100644
--- a/src/fsatrace.c
+++ b/src/fsatrace.c
@@ -127,9 +127,11 @@
 		fatal("allocating shared memory (%d)", err);
 	snprintf(envout, sizeof(envout), ENVOUT "=%s", out);
 	putenv(envout);
+#ifdef _WIN32
 	// Workaround, bash distributed with ghc 8.6.5 seems to discard most
 	// environment variables, pass FSAT_OUT as the first PATH component.
 	snprintf(envout, sizeof(envout), "PATH=%s;%s", out, getenv("PATH"));
+#endif
 	putenv(envout);
 	fflush(stdout);
 	opts = (const unsigned char *)argv[1];
diff --git a/src/win/handle.c b/src/win/handle.c
index 090f2df..1baab8d 100644
--- a/src/win/handle.c
+++ b/src/win/handle.c
@@ -6,10 +6,10 @@
 #include "dbg.h"
 #include "handle.h"
 
-char * handlePath(char * dst, HANDLE h) {
+const char * handlePath(char * dst, HANDLE h) {
 	WCHAR wbuf[PATH_MAX];
 	DWORD len;
-	if (h)
+	if (h && h != INVALID_HANDLE_VALUE)
 		len = GetFinalPathNameByHandleW(h, wbuf, PATH_MAX, FILE_NAME_NORMALIZED);
 	else
 		len = 0;
diff --git a/src/win/handle.h b/src/win/handle.h
index 0d0bada..5d3d5b0 100644
--- a/src/win/handle.h
+++ b/src/win/handle.h
@@ -1 +1 @@
-char * handlePath(char * dst, HANDLE h);
+const char * handlePath(char * dst, HANDLE h);
diff --git a/src/win/hooks.c b/src/win/hooks.c
index d3b0c23..67b6dec 100644
--- a/src/win/hooks.c
+++ b/src/win/hooks.c
@@ -1,12 +1,8 @@
 #include <stdbool.h>
-#if defined _MSC_VER
 #include <windows.h>
-#endif
 #include <winternl.h>
 #include <limits.h>
-#include <stdbool.h>
 #include <processthreadsapi.h>
-#undef ASSERT
 #include "dbg.h"
 #include "../emit.h"
 #include "handle.h"
@@ -54,8 +50,23 @@
 
 static volatile unsigned g_nesting = 0;
 
-#define ORIG(x) do { g_nesting++; r = x; if (g_nesting > 1) goto done; } while(0)
-#define DONE done: do { --g_nesting; return r; } while (0)
+static const bool g_debug = false;
+
+#define ORIG(x)												\
+		do {												\
+				g_nesting++;								\
+				if (g_debug) pr("%s %d", #x, g_nesting);	\
+				r = o##x;									\
+				if (g_nesting > 1)							\
+						goto done;							\
+		} while(0)
+#define DONE							 \
+		done:							 \
+		do {							 \
+				--g_nesting;			 \
+				if (g_debug) pr("done"); \
+				return r;				 \
+		} while (0)
 
 static const int fop(ACCESS_MASK am, ULONG co) {
 	int op;
@@ -65,36 +76,37 @@
 		op = '?';
 	else if (co & FILE_DELETE_ON_CLOSE)
 		op = 'd';
-	else if (am & DELETE)
-		op = 'd';
 	else if (am & GENERIC_WRITE)
 		op = 'w';
-	else if (am & (GENERIC_READ | READ_CONTROL))
+	else if (am & GENERIC_READ)
 		op = 'r';
 	else
 		op = '?';
 	return op;
 }
 
-static char * oaPath(char * buf, POBJECT_ATTRIBUTES oa) {
+static const char * oaPath(char * buf, const POBJECT_ATTRIBUTES oa) {
 	size_t l = 0;
+	if (!oa) return NULL;
 	if (oa->RootDirectory) {
-		handlePath(buf, oa->RootDirectory);
-		l = strlen(buf);
-		buf[l] = '/';
-		buf[++l] = 0;
+		const char * p = handlePath(buf, oa->RootDirectory);
+		if (p) {
+				l = strlen(p);
+				buf[l++] = '/';
+				buf[l] = 0;
+		}
 	}
 	return utf8PathFromWide(buf+l, oa->ObjectName->Buffer, oa->ObjectName->Length/2);
 }
 
-static void femit(bool ok, HANDLE h, POBJECT_ATTRIBUTES oa, int op) {
+static void femit(bool ok, HANDLE h, const POBJECT_ATTRIBUTES oa, int op) {
 	if (op) {
 		IO_STATUS_BLOCK sb;
 		FILE_STANDARD_INFORMATION si;
 		oNtQueryInformationFile(h, &sb, &si, sizeof(si), FileStandardInformation);
 		if (!si.Directory) {
 			char buf[PATH_MAX];
-			char * p = oaPath(buf, oa);
+			const char * p = oaPath(buf, oa);
 			if (!p)
 					p = handlePath(buf, h);
 			if (!p)
@@ -116,15 +128,10 @@
                                     PVOID bu,
                                     ULONG le) {
 	NTSTATUS r;
-	D;
-	ORIG(oNtCreateFile(ph, am, oa, sb, as, fa, sa, cd, co, bu, le));
-#ifdef TRACE
-	if (true) {
-		char buf[PATH_MAX];
-		pr("creat r %d am %x co %x fa %x sa %x cd %x op %c %s", r, am, co, fa, sa, cd, fop(am, co), oaPath(buf, oa));
-	}
-#endif
-	femit(NT_SUCCESS(r), *ph, oa, fop(am, co));
+	if (ph)
+		*ph=INVALID_HANDLE_VALUE;
+	ORIG(NtCreateFile(ph, am, oa, sb, as, fa, sa, cd, co, bu, le));
+	femit(NT_SUCCESS(r), ph? *ph : INVALID_HANDLE_VALUE, oa, fop(am, co));
 	DONE;
 }
 
@@ -135,25 +142,17 @@
                                   ULONG sa,
                                   ULONG oo) {
 	NTSTATUS r;
-	D;
-	*ph = 0;
-	ORIG(oNtOpenFile(ph, am, oa, sb, sa, oo));
-#ifdef TRACE
-	if (true) {
-		char buf[PATH_MAX];
-		char hbuf[PATH_MAX];
-		pr("open r %d am %x oo %x p op %c %s %s", r, am, oo, fop(am, oo), oaPath(buf, oa), handlePath(hbuf, *ph));
-	}
-#endif
-	femit(NT_SUCCESS(r), *ph, oa, fop(am, oo));
+	if (ph)
+		*ph=INVALID_HANDLE_VALUE;
+	ORIG(NtOpenFile(ph, am, oa, sb, sa, oo));
+	femit(NT_SUCCESS(r), ph? *ph : INVALID_HANDLE_VALUE, oa, fop(am, oo));
 	DONE;
 }
 
 static NTSTATUS NTAPI hNtDeleteFile(POBJECT_ATTRIBUTES oa) {
 	NTSTATUS r;
 	char buf[PATH_MAX];
-	D;
-	ORIG(oNtDeleteFile(oa));
+	ORIG(NtDeleteFile(oa));
 	emitOp(NT_SUCCESS(r), 'd', oaPath(buf, oa), 0);
 	DONE;
 }
@@ -165,27 +164,26 @@
                                             FILE_INFORMATION_CLASS ic) {
 	NTSTATUS r;
 	char buf[PATH_MAX];
-	char buf2[PATH_MAX];
 #ifdef _MSC_VER
 	PFILE_RENAME_INFO ri = (PFILE_RENAME_INFO)fi;
 #else
 	PFILE_RENAME_INFORMATION ri = (PFILE_RENAME_INFORMATION)fi;
 #endif
-	char * opath = handlePath(buf, fh);
+	const char * opath = handlePath(buf, fh);
 	bool ok;
-	D;
-	ORIG(oNtSetInformationFile(fh, sb, fi, ln, ic));
+	ORIG(NtSetInformationFile(fh, sb, fi, ln, ic));
 	ok = NT_SUCCESS(r);
 	switch (ic) {
 	case FileBasicInformation:
 		emitOp(ok, 't', opath, 0);
 		break;
-	case FileRenameInformation:
+	case FileRenameInformation: {
+		char buf2[PATH_MAX];
 		emitOp(ok, opath? 'm' : 'M',
 		       utf8PathFromWide(buf2, ri->FileName,
 								ri->FileNameLength / sizeof(ri->FileName[0])),
 		       opath);
-		break;
+	}   break;
 	case FileDispositionInformation:
 		emitOp(ok, 'd', opath, 0);
 		break;
@@ -193,6 +191,7 @@
 		emitOp(ok, 'w', opath, 0);
 		break;
 	default:
+		emitOp(ok, '?', opath, 0);
 		break;
 	}
 	DONE;
@@ -205,18 +204,18 @@
                                               FILE_INFORMATION_CLASS ic) {
 	NTSTATUS r;
 	char buf[PATH_MAX];
-	D;
-	ORIG(oNtQueryInformationFile(fh, sb, fi, ln, ic));
-#ifdef TRACE
-	pr("queryinfofile r %d ic %x", r, ic);
-#endif
+	const char * opath;
+	bool ok;
+	ORIG(NtQueryInformationFile(fh, sb, fi, ln, ic));
+	ok = NT_SUCCESS(r);
+	opath = handlePath(buf, fh);
 	switch (ic) {
 	case FileAllInformation:
 	case FileNetworkOpenInformation:
-		emitOp(NT_SUCCESS(r), 'q', handlePath(buf, fh), 0);
+		emitOp(ok, 'q', opath, 0);
 		break;
 	default:
-		emitOp(NT_SUCCESS(r), '?', handlePath(buf, fh), 0);
+		emitOp(ok, '?', opath, 0);
 		break;
 	}
 	DONE;
@@ -226,11 +225,7 @@
 static NTSTATUS NTAPI hNtQueryFullAttributesFile(POBJECT_ATTRIBUTES oa, PFILE_NETWORK_OPEN_INFORMATION oi) {
 	NTSTATUS r;
 	char buf[PATH_MAX];
-	D;
-	ORIG(oNtQueryFullAttributesFile(oa, oi));
-#ifdef TRACE
-	pr("queryfull %s", oaPath(buf, oa));
-#endif
+	ORIG(NtQueryFullAttributesFile(oa, oi));
 	emitOp(NT_SUCCESS(r), 'q', oaPath(buf, oa), 0);
 	DONE;
 }
@@ -238,12 +233,12 @@
 static NTSTATUS NTAPI hNtResumeThread(HANDLE th, PULONG sc) {
 	NTSTATUS r;
 	DWORD pid;
-	D;
 	pid = GetProcessIdOfThread(th);
+	if (g_debug) pr("patch %d", pid);
 	if (!patchInstalled(pid))
 		injectPID(pid);
-	r = oNtResumeThread(th, sc);
-	return r;
+	ORIG(NtResumeThread(th, sc));
+	DONE;
 }
 
 
diff --git a/src/win/proc.c b/src/win/proc.c
index dd0c760..f94454f 100644
--- a/src/win/proc.c
+++ b/src/win/proc.c
@@ -53,7 +53,7 @@
 					EMITN('\\', 2*ns+1);
 					EMIT('"');
 					break;
-				default: 
+				default:
 					EMITN('\\', ns);
 					EMIT(arg[i]);
 				}
@@ -86,10 +86,10 @@
 	int argc;
 	LPWSTR * wargv = CommandLineToArgvW(cl, &argc);
 	WCHAR args[MAXCMD];
-	fprintf(stderr, "original=%ls\n", cl);	
+	fprintf(stderr, "original=%ls\n", cl);
 	for (i = 4; i < argc; i++)
 		fprintf(stderr, "argv[%d]=%ls\n", i-4, wargv[i]);
-	argvToCommandLine(args, argc-4, wargv+4);	
+	argvToCommandLine(args, argc-4, wargv+4);
 	fprintf(stderr, "composed=%ls\n", args);
 	LocalFree(wargv);
 }
@@ -116,9 +116,9 @@
 		injectProcess(pi.hProcess);
 	CHK(ERR_PROC_EXEC, -1 == ResumeThread(pi.hThread));
 	CHK(ERR_PROC_WAIT, WAIT_OBJECT_0 != WaitForSingleObject(pi.hThread, INFINITE));
-	CHK(ERR_PROC_WAIT, WAIT_OBJECT_0 != WaitForSingleObject(pi.hProcess, INFINITE));	
+	CHK(ERR_PROC_WAIT, WAIT_OBJECT_0 != WaitForSingleObject(pi.hProcess, INFINITE));
 	CHK(ERR_PROC_WAIT, !GetExitCodeProcess(pi.hProcess, &drc));
-	CHK(ERR_PROC_FORK, !CloseHandle(pi.hThread));	
+	CHK(ERR_PROC_FORK, !CloseHandle(pi.hThread));
 	CHK(ERR_PROC_FORK, !CloseHandle(pi.hProcess));
 	if (err == ERR_PROC_OK)
 		*rc = drc;
diff --git a/test/Utils.hs b/test/Utils.hs
index f0ca378..cddca53 100644
--- a/test/Utils.hs
+++ b/test/Utils.hs
@@ -20,18 +20,18 @@
 import           Data.Char
 import           Data.List.Extra
 import           System.Exit
-import           System.IO
-import           System.Process
 import           System.FilePath
 import           System.Info.Extra
+import           System.IO
+import           System.Process
 import           Test.QuickCheck
 import           Test.QuickCheck.Monadic
 --import           Debug.Trace
 
 data Env = Env
     { shellMode :: ShellMode
-    , tmpDir :: FilePath
-    , pwdDir :: FilePath
+    , tmpDir    :: FilePath
+    , pwdDir    :: FilePath
     }
 
 type Prop = Reader Env Property
@@ -95,6 +95,7 @@
       let r = fmap (cleanup . map (fmap Path) . parseFSATrace) out
       let ok = fmap cleanup r == Just (cleanup res)
       unless ok $ liftIO $ do
+        putStrLn $ "For command " ++ show cmd
         putStrLn $ "Expecting " ++ show (cleanup res)
         putStrLn $ "Got       " ++ show r
       assert ok
@@ -111,7 +112,7 @@
         quoted :: String -> String
         quoted "|" = "|"
         quoted ">" = ">"
-        quoted x = "\"" ++ x ++ "\""
+        quoted x   = "\"" ++ x ++ "\""
 
 
 systemStderr :: [String] -> IO (Maybe String)
@@ -135,7 +136,7 @@
     deriving Eq
 
 instance Show FSATest where
-  show FSATest = "fsatest"
+  show FSATest   = "fsatest"
   show FSATest32 = "fsatest32"
 
 instance Arbitrary FSATest where
@@ -174,5 +175,5 @@
 
 no32to64 :: FSATest -> Act -> Act
 no32to64 FSATest32 (ActE _ xs) = ActE FSATest32 $ map (no32to64 FSATest32) xs
-no32to64 _ (ActE p xs) = ActE p $ map (no32to64 p) xs
-no32to64 _ x = x
+no32to64 _ (ActE p xs)         = ActE p $ map (no32to64 p) xs
+no32to64 _ x                   = x