diff options
Diffstat (limited to 'lib/intercept/intercept.cpp')
-rw-r--r-- | lib/intercept/intercept.cpp | 141 |
1 files changed, 132 insertions, 9 deletions
diff --git a/lib/intercept/intercept.cpp b/lib/intercept/intercept.cpp index 65514ae2..7a33b610 100644 --- a/lib/intercept/intercept.cpp +++ b/lib/intercept/intercept.cpp @@ -22,6 +22,7 @@ #endif #include <errno.h> +#include <stdarg.h> #ifdef HAVE_DLFCN_H #include <dlfcn.h> @@ -84,6 +85,12 @@ static closedir_t* closedir_real = NULL; static lstat_t* lstat_real = NULL; static lstat_t* lstat_hook = NULL; static const char* lstat_file = NULL; +static lstat_t* stat_real = NULL; +static lstat_t* stat_hook = NULL; +static const char* stat_file = NULL; + +static lstat_post_hook_t* lstat_post_hook = NULL; +static lstat_post_hook_t* stat_post_hook = NULL; #define SIZE_ALWAYS_ERROR -773 @@ -97,7 +104,10 @@ void intercept_clear_setup() intercept_filepos = 0; intercept_delay_ms = 0; readdir_hook = NULL; + stat_hook = NULL; lstat_hook = NULL; + stat_post_hook = NULL; + lstat_post_hook = NULL; } bool intercept_triggered() @@ -222,8 +232,16 @@ int intercept_reterr() } \ } +#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64 + #define DEFINE_ONLY_OPEN64 +#endif + extern "C" int -open(const char *path, int flags, mode_t mode) +#ifdef DEFINE_ONLY_OPEN64 + open64(const char *path, int flags, ...) +#else + open(const char *path, int flags, ...) +#endif // DEFINE_ONLY_OPEN64 { if(intercept_count > 0) { @@ -236,6 +254,15 @@ open(const char *path, int flags, mode_t mode) } } + mode_t mode = 0; + if (flags & O_CREAT) + { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + #ifdef PLATFORM_NO_SYSCALL int r = TEST_open(path, flags, mode); #else @@ -257,14 +284,27 @@ open(const char *path, int flags, mode_t mode) return r; } +#ifndef DEFINE_ONLY_OPEN64 extern "C" int -open64(const char *path, int flags, mode_t mode) +// open64(const char *path, int flags, mode_t mode) +// open64(const char *path, int flags, ...) +open64 (__const char *path, int flags, ...) { + mode_t mode = 0; + if (flags & O_CREAT) + { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + // With _FILE_OFFSET_BITS set to 64 this should really use (flags | // O_LARGEFILE) here, but not actually necessary for the tests and not // worth the trouble finding O_LARGEFILE return open(path, flags, mode); } +#endif // !DEFINE_ONLY_OPEN64 extern "C" int close(int d) @@ -375,12 +415,12 @@ void intercept_setup_readdir_hook(const char *dirname, readdir_t hookfn) if (hookfn != NULL) { - TRACE2("readdir hooked to %p for %s\n", hookfn, dirname); + BOX_TRACE("readdir hooked to " << hookfn << " for " << dirname); } else if (intercept_filename != NULL) { - TRACE2("readdir unhooked from %p for %s\n", readdir_hook, - intercept_filename); + BOX_TRACE("readdir unhooked from " << readdir_hook << + " for " << intercept_filename); } intercept_filename = dirname; @@ -392,11 +432,11 @@ void intercept_setup_lstat_hook(const char *filename, lstat_t hookfn) /* if (hookfn != NULL) { - TRACE2("lstat hooked to %p for %s\n", hookfn, filename); + BOX_TRACE("lstat hooked to " << hookfn << " for " << filename); } else { - TRACE2("lstat unhooked from %p for %s\n", lstat_hook, + BOX_TRACE("lstat unhooked from " << lstat_hook << " for " << lstat_file); } */ @@ -405,6 +445,40 @@ void intercept_setup_lstat_hook(const char *filename, lstat_t hookfn) lstat_hook = hookfn; } +void intercept_setup_lstat_post_hook(lstat_post_hook_t hookfn) +{ + /* + if (hookfn != NULL) + { + BOX_TRACE("lstat hooked to " << hookfn << " for " << filename); + } + else + { + BOX_TRACE("lstat unhooked from " << lstat_hook << " for " << + lstat_file); + } + */ + + lstat_post_hook = hookfn; +} + +void intercept_setup_stat_post_hook(lstat_post_hook_t hookfn) +{ + /* + if (hookfn != NULL) + { + BOX_TRACE("lstat hooked to " << hookfn << " for " << filename); + } + else + { + BOX_TRACE("lstat unhooked from " << lstat_hook << " for " << + lstat_file); + } + */ + + stat_post_hook = hookfn; +} + static void * find_function(const char *pName) { dlerror(); @@ -534,10 +608,15 @@ lstat(const char *file_name, STAT_STRUCT *buf) if (lstat_hook == NULL || strcmp(file_name, lstat_file) != 0) { #ifdef LINUX_WEIRD_LSTAT - return lstat_real(ver, file_name, buf); + int ret = lstat_real(ver, file_name, buf); #else - return lstat_real(file_name, buf); + int ret = lstat_real(file_name, buf); #endif + if (lstat_post_hook != NULL) + { + ret = lstat_post_hook(ret, file_name, buf); + } + return ret; } #ifdef LINUX_WEIRD_LSTAT @@ -547,4 +626,48 @@ lstat(const char *file_name, STAT_STRUCT *buf) #endif } +extern "C" int +#ifdef LINUX_WEIRD_LSTAT +__xstat(int ver, const char *file_name, STAT_STRUCT *buf) +#else +stat(const char *file_name, STAT_STRUCT *buf) +#endif +{ + if (stat_real == NULL) + { + #ifdef LINUX_WEIRD_LSTAT + stat_real = (lstat_t*)find_function("__xstat"); + #else + stat_real = (lstat_t*)find_function("stat"); + #endif + } + + if (stat_real == NULL) + { + perror("cannot find real stat"); + errno = ENOSYS; + return -1; + } + + if (stat_hook == NULL || strcmp(file_name, stat_file) != 0) + { + #ifdef LINUX_WEIRD_LSTAT + int ret = stat_real(ver, file_name, buf); + #else + int ret = stat_real(file_name, buf); + #endif + if (stat_post_hook != NULL) + { + ret = stat_post_hook(ret, file_name, buf); + } + return ret; + } + + #ifdef LINUX_WEIRD_LSTAT + return stat_hook(ver, file_name, buf); + #else + return stat_hook(file_name, buf); + #endif +} + #endif // n PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE |