/* Copyright (C) 2004 Anthony Green Do whatever you want with this, but don't blame me for anything related to it. This experiment demonstrates hooking into the C library's open() routine in order to redirect file open requests. */ #define _GNU_SOURCE #include #include #include #include /* Use the convenient apache portable runtime for hashtables, global mutexes, etc. */ #include "apr.h" #include "apr_general.h" #include "apr_pools.h" #include "apr_hash.h" static int (*open_) (const char *pathname, int flags); apr_pool_t *mempool_; apr_hash_t *filehash_; /* Populate a hashtable with filename mappings. */ static void fill_filehash (const char *fname) { /* FIXME: buffer overrun opportunity */ char key[PATH_MAX + 1]; char value[PATH_MAX + 1]; FILE *stream = fopen (fname, "r"); /* fname currently just contains filename pairs. The first is the name on the user's workstation, and the second is our local name on the build machine. */ int rc; do { /* FIXME: this doesn't work for filenames with whitespace. */ rc = fscanf (stream, "%s", key); if (rc != EOF) { rc = fscanf (stream, "%s", value); if (rc != EOF) apr_hash_set (filehash_, key, APR_HASH_KEY_STRING, value); } } while (rc != EOF); fclose (stream); } /* Force constr to execute prior to main(). */ static void constr (void) __attribute__ ((constructor)); static void constr (void) { apr_initialize (); atexit (apr_terminate); /* Get a pointer to the real open(). */ open_ = dlsym (RTLD_NEXT, "open"); if (open_ == NULL) abort (); /* Create and populate our file name mapping hashtable. */ if (apr_pool_create (&mempool_, NULL) != APR_SUCCESS) abort (); if ((filehash_ = apr_hash_make (mempool_)) == NULL) abort (); /* This is just an experiment. So let's read out of a manually created file for now. */ fill_filehash ("/tmp/fhash.txt"); } /** Open a file. Look up pathname in our database. If it exists, then open the local file pathname maps to. Otherwise ask the build client for a copy. */ int open (const char *pathname, int flags) { const char *lpathname = (const char *) apr_hash_get (filehash_, pathname, APR_HASH_KEY_STRING); /* This is just an experiment. So fail gracefully if we don't find a match for a filename. */ return open_ (lpathname ? lpathname : pathname, flags); }