From 2185a70fa4eec7a42dc3c0cce61ece4b71b0a7a0 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 16 Jan 2022 21:41:41 +0000 Subject: [PATCH] libredirect: add support for mkstemp family of functions --- pkgs/build-support/libredirect/default.nix | 4 +- pkgs/build-support/libredirect/libredirect.c | 65 ++++++++++++++++++++ pkgs/build-support/libredirect/test.c | 40 ++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/pkgs/build-support/libredirect/default.nix b/pkgs/build-support/libredirect/default.nix index 9a35db97c9f..4c344a24b93 100644 --- a/pkgs/build-support/libredirect/default.nix +++ b/pkgs/build-support/libredirect/default.nix @@ -57,7 +57,9 @@ else stdenv.mkDerivation rec { ''} if [ -n "$doInstallCheck" ]; then - $CC -Wall -std=c99 -D_POSIX_C_SOURCE=200809L -O3 test.c -o test + $CC -Wall -std=c99 \ + ${lib.optionalString (!stdenv.isDarwin) "-D_GNU_SOURCE"} \ + -O3 test.c -o test fi runHook postBuild diff --git a/pkgs/build-support/libredirect/libredirect.c b/pkgs/build-support/libredirect/libredirect.c index e33199402c4..a59bc1bbaa3 100644 --- a/pkgs/build-support/libredirect/libredirect.c +++ b/pkgs/build-support/libredirect/libredirect.c @@ -84,6 +84,13 @@ static const char * rewrite(const char * path, char * buf) return path; } +static char * rewrite_non_const(char * path, char * buf) +{ + // as long as the argument `path` is non-const, we can consider discarding + // the const qualifier of the return value to be safe. + return (char *)rewrite(path, buf); +} + static int open_needs_mode(int flags) { #ifdef O_TMPFILE @@ -378,3 +385,61 @@ WRAPPER(int, rmdir)(const char *path) return rmdir_real(rewrite(path, buf)); } WRAPPER_DEF(rmdir) + +static void copy_temp_wildcard(char * dest, char * src, int suffixlen) { + int dest_len = strnlen(dest, PATH_MAX); + int src_len = strnlen(src, PATH_MAX); + memcpy(dest + dest_len - (6 + suffixlen), src + src_len - (6 + suffixlen), 6); +} + +WRAPPER(int, mkstemp)(char *template) +{ + int (*mkstemp_real) (char *template) = LOOKUP_REAL(mkstemp); + char buf[PATH_MAX]; + char * rewritten = rewrite_non_const(template, buf); + int retval = mkstemp_real(rewritten); + if (retval >= 0 && rewritten != template) { + copy_temp_wildcard(template, rewritten, 0); + } + return retval; +} +WRAPPER_DEF(mkstemp) + +WRAPPER(int, mkostemp)(char *template, int flags) +{ + int (*mkostemp_real) (char *template, int flags) = LOOKUP_REAL(mkostemp); + char buf[PATH_MAX]; + char * rewritten = rewrite_non_const(template, buf); + int retval = mkostemp_real(rewritten, flags); + if (retval >= 0 && rewritten != template) { + copy_temp_wildcard(template, rewritten, 0); + } + return retval; +} +WRAPPER_DEF(mkostemp) + +WRAPPER(int, mkstemps)(char *template, int suffixlen) +{ + int (*mkstemps_real) (char *template, int suffixlen) = LOOKUP_REAL(mkstemps); + char buf[PATH_MAX]; + char * rewritten = rewrite_non_const(template, buf); + int retval = mkstemps_real(rewritten, suffixlen); + if (retval >= 0 && rewritten != template) { + copy_temp_wildcard(template, rewritten, suffixlen); + } + return retval; +} +WRAPPER_DEF(mkstemps) + +WRAPPER(int, mkostemps)(char *template, int suffixlen, int flags) +{ + int (*mkostemps_real) (char *template, int suffixlen, int flags) = LOOKUP_REAL(mkostemps); + char buf[PATH_MAX]; + char * rewritten = rewrite_non_const(template, buf); + int retval = mkostemps_real(rewritten, suffixlen, flags); + if (retval >= 0 && rewritten != template) { + copy_temp_wildcard(template, rewritten, suffixlen); + } + return retval; +} +WRAPPER_DEF(mkostemps) diff --git a/pkgs/build-support/libredirect/test.c b/pkgs/build-support/libredirect/test.c index c546a895828..f15b44ff3d8 100644 --- a/pkgs/build-support/libredirect/test.c +++ b/pkgs/build-support/libredirect/test.c @@ -1,9 +1,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -43,11 +45,25 @@ void test_subprocess(void) { assert(system(SUBTEST) == 0); } +void assert_mktemp_path( + const char * orig_prefix, + const char * orig_suffix, + const char * updated +) { + // prefix unchanged + assert(strncmp(updated, orig_prefix, strlen(orig_prefix)) == 0); + // wildcards replaced + assert(strcmp(updated + strlen(orig_prefix), "XXXXXX") != 0); + // suffix unchanged + assert(strcmp(updated + strlen(orig_prefix) + 6, orig_suffix) == 0); +} + int main(int argc, char *argv[]) { FILE *testfp; int testfd; struct stat testsb; + char buf[PATH_MAX]; testfp = fopen(TESTPATH, "r"); assert(testfp != NULL); @@ -77,6 +93,30 @@ int main(int argc, char *argv[]) #endif assert(unlinkat(123, TESTDIR "/dir-mkdirat", AT_REMOVEDIR) == 0); + strncpy(buf, TESTDIR "/tempXXXXXX", PATH_MAX); + testfd = mkstemp(buf); + assert(testfd > 0); + assert_mktemp_path(TESTDIR "/temp", "", buf); + close(testfd); + + strncpy(buf, TESTDIR "/tempXXXXXX", PATH_MAX); + testfd = mkostemp(buf, 0); + assert(testfd > 0); + assert_mktemp_path(TESTDIR "/temp", "", buf); + close(testfd); + + strncpy(buf, TESTDIR "/tempXXXXXX.test", PATH_MAX); + testfd = mkstemps(buf, strlen(".test")); + assert(testfd > 0); + assert_mktemp_path(TESTDIR "/temp", ".test", buf); + close(testfd); + + strncpy(buf, TESTDIR "/tempXXXXXX.test", PATH_MAX); + testfd = mkostemps(buf, strlen(".test"), 0); + assert(testfd > 0); + assert_mktemp_path(TESTDIR "/temp", ".test", buf); + close(testfd); + test_spawn(); test_system();