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