#include "apr.h"
#include "apr_mmap.h"
#include "apr_strings.h"
+#include "apr_hash.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
} a_file;
typedef struct {
- apr_array_header_t *files;
+ apr_hash_t *fileht;
} a_server_config;
{
a_server_config *sconf = apr_palloc(p, sizeof(*sconf));
- sconf->files = apr_array_make(p, 20, sizeof(a_file));
+ sconf->fileht = apr_hash_make(p);
return sconf;
}
static apr_status_t cleanup_file_cache(void *sconfv)
{
a_server_config *sconf = sconfv;
- size_t n;
a_file *file;
+ apr_hash_index_t *hi;
- n = sconf->files->nelts;
- file = (a_file *)sconf->files->elts;
- while(n) {
+ /* Iterate over the file hash table and clean up each entry */
+ for (hi = apr_hash_first(sconf->fileht); hi; hi=apr_hash_next(hi)) {
+ apr_hash_this(hi, NULL, NULL, &file);
#if APR_HAS_MMAP
if (file->is_mmapped) {
apr_mmap_delete(file->mm);
}
- else
#endif
#if APR_HAS_SENDFILE
+ if (!file->is_mmapped) {
apr_file_close(file->file);
+ }
#endif
- ++file;
- --n;
}
return APR_SUCCESS;
}
-static const char *cachefile(cmd_parms *cmd, void *dummy, const char *filename)
-
+static void cache_the_file(cmd_parms *cmd, const char *filename, int mmap)
{
- /* ToDo:
- * Disable the file cache on a Windows 9X box. APR_HAS_SENDFILE will be
- * defined in an Apache for Windows build, but apr_sendfile returns
- * APR_ENOTIMPL on Windows 9X because TransmitFile is not available.
- */
-
-#if APR_HAS_SENDFILE
a_server_config *sconf;
a_file *new_file;
a_file tmp;
apr_file_t *fd = NULL;
apr_status_t rc;
+ const char *fspec;
- /* canonicalize the file name? */
- /* os_canonical... */
- /* XXX: uh... yea, or expect them to be -very- accurate typists */
- if ((rc = apr_stat(&tmp.finfo, filename, APR_FINFO_MIN,
+ fspec = ap_os_case_canonical_filename(cmd->pool, filename);
+ if ((rc = apr_stat(&tmp.finfo, fspec, APR_FINFO_MIN,
cmd->temp_pool)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
- "mod_file_cache: unable to stat(%s), skipping", filename);
- return NULL;
+ "mod_file_cache: unable to stat(%s), skipping", fspec);
+ return;
}
if (tmp.finfo.filetype != APR_REG) {
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
- "mod_file_cache: %s isn't a regular file, skipping", filename);
- return NULL;
+ "mod_file_cache: %s isn't a regular file, skipping", fspec);
+ return;
}
- rc = apr_file_open(&fd, filename, APR_READ | APR_XTHREAD, APR_OS_DEFAULT, cmd->pool);
+ rc = apr_file_open(&fd, fspec, APR_READ | APR_XTHREAD, APR_OS_DEFAULT, cmd->pool);
if (rc != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
- "mod_file_cache: unable to open(%s, O_RDONLY), skipping", filename);
- return NULL;
+ "mod_file_cache: unable to open(%s, O_RDONLY), skipping", fspec);
+ return;
}
- tmp.file = fd;
- tmp.filename = apr_pstrdup(cmd->pool, filename);
- apr_rfc822_date(tmp.mtimestr, tmp.finfo.mtime);
- apr_snprintf(tmp.sizestr, sizeof tmp.sizestr, "%" APR_OFF_T_FMT, tmp.finfo.size);
+
+ /* WooHoo, we have a file to put in the cache */
+ new_file = apr_pcalloc(cmd->pool, sizeof(a_file));
+ new_file->finfo = tmp.finfo;
+
+ if (mmap) {
+ /* MMAPFile directive. MMAP'ing the file */
+ if ((rc = apr_mmap_create(&new_file->mm, fd, 0, new_file->finfo.size,
+ APR_MMAP_READ, cmd->pool)) != APR_SUCCESS) {
+ apr_file_close(fd);
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
+ "mod_file_cache: unable to mmap %s, skipping", filename);
+ return;
+ }
+ apr_file_close(fd);
+ new_file->is_mmapped = TRUE;
+ }
+ else {
+ /* CacheFile directive. Caching the file handle */
+ new_file->is_mmapped = FALSE;
+ new_file->file = fd;
+ }
+
+ new_file->filename = fspec;
+ apr_rfc822_date(new_file->mtimestr, new_file->finfo.mtime);
+ apr_snprintf(new_file->sizestr, sizeof new_file->sizestr, "%" APR_OFF_T_FMT, new_file->finfo.size);
+
sconf = ap_get_module_config(cmd->server->module_config, &file_cache_module);
- new_file = apr_array_push(sconf->files);
- *new_file = tmp;
- if (sconf->files->nelts == 1) {
+ apr_hash_set(sconf->fileht, new_file->filename, strlen(new_file->filename), new_file);
+
+ if (apr_hash_count(sconf->fileht) == 1) {
/* first one, register the cleanup */
apr_pool_cleanup_register(cmd->pool, sconf, cleanup_file_cache, apr_pool_cleanup_null);
}
+}
- new_file->is_mmapped = FALSE;
-
- return NULL;
+static const char *cachefilehandle(cmd_parms *cmd, void *dummy, const char *filename)
+{
+#if APR_HAS_SENDFILE
+ cache_the_file(cmd, filename, 0);
#else
- /* Sendfile not supported on this platform */
+ /* Sendfile not supported by this OS */
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
- "mod_file_cache: unable to cache file: %s. Sendfile is not supported on this OS", filename);
- return NULL;
+ "mod_file_cache: unable to cache file: %s. Sendfile is not supported on this OS", fspec);
#endif
+ return NULL;
}
-
-static const char *mmapfile(cmd_parms *cmd, void *dummy, const char *filename)
+static const char *cachefilemmap(cmd_parms *cmd, void *dummy, const char *filename)
{
#if APR_HAS_MMAP
- a_server_config *sconf;
- a_file *new_file;
- a_file tmp;
- apr_file_t *fd = NULL;
- apr_status_t rc;
- const char *fspec;
-
- fspec = ap_os_case_canonical_filename(cmd->pool, filename);
- if ((rc = apr_stat(&tmp.finfo, fspec, APR_FINFO_MIN,
- cmd->temp_pool)) != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
- "mod_file_cache: unable to stat(%s), skipping", filename);
- return NULL;
- }
- if ((tmp.finfo.filetype) != APR_REG) {
- ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
- "mod_file_cache: %s isn't a regular file, skipping", filename);
- return NULL;
- }
- if ((rc = apr_file_open(&fd, fspec, APR_READ, APR_OS_DEFAULT,
- cmd->temp_pool)) != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
- "mod_file_cache: unable to open %s, skipping",
- filename);
- return NULL;
- }
- if ((rc = apr_mmap_create(&tmp.mm, fd, 0, tmp.finfo.size, APR_MMAP_READ, cmd->pool)) != APR_SUCCESS) {
- apr_file_close(fd);
- ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
- "mod_file_cache: unable to mmap %s, skipping", filename);
- return NULL;
- }
- apr_file_close(fd);
- tmp.filename = fspec;
- apr_rfc822_date(tmp.mtimestr, tmp.finfo.mtime);
- apr_snprintf(tmp.sizestr, sizeof tmp.sizestr, "%" APR_OFF_T_FMT, tmp.finfo.size);
- sconf = ap_get_module_config(cmd->server->module_config, &file_cache_module);
- new_file = apr_array_push(sconf->files);
- *new_file = tmp;
- if (sconf->files->nelts == 1) {
- /* first one, register the cleanup */
- apr_pool_cleanup_register(cmd->pool, sconf, cleanup_file_cache, apr_pool_cleanup_null);
- }
-
- new_file->is_mmapped = TRUE;
-
- return NULL;
+ cache_the_file(cmd, filename, 1);
#else
- /* MMAP not supported on this platform*/
- return NULL;
+ /* MMAP not supported by this OS */
+ ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
+ "mod_file_cache: unable to cache file: %s. MMAP is not supported by this OS", fspec);
#endif
-}
-
-
-static int file_compare(const void *av, const void *bv)
-{
- const a_file *a = av;
- const a_file *b = bv;
-
- return strcmp(a->filename, b->filename);
+ return NULL;
}
static void file_cache_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
- a_server_config *sconf;
- a_file *elts;
- int nelts;
-
- /* sort the elements of the main_server, by filename */
- sconf = ap_get_module_config(s->module_config, &file_cache_module);
- elts = (a_file *)sconf->files->elts;
- nelts = sconf->files->nelts;
- qsort(elts, nelts, sizeof(a_file), file_compare);
-
- /* and make the virtualhosts share the same thing */
- for (s = s->next; s; s = s->next) {
- ap_set_module_config(s->module_config, &file_cache_module, sconf);
- }
+ /* Hummm, anything to do here? */
}
/* If it's one of ours, fill in r->finfo now to avoid extra stat()... this is a
sconf = ap_get_module_config(r->server->module_config, &file_cache_module);
/* we only operate when at least one cachefile directive was used */
- if (apr_is_empty_table(sconf->files))
+ if (!apr_hash_count(sconf->fileht)) {
return DECLINED;
+ }
res = ap_core_translate(r);
if (res != OK || !r->filename) {
return res;
}
- tmp.filename = r->filename;
- match = (a_file *)bsearch(&tmp, sconf->files->elts, sconf->files->nelts,
- sizeof(a_file), file_compare);
-
+ /* search the cache */
+ match = (a_file *) apr_hash_get(sconf->fileht, r->filename, APR_HASH_KEY_STRING);
if (match == NULL)
return DECLINED;
- /* pass bsearch results to handler */
+ /* pass search results to handler */
ap_set_module_config(r->request_config, &file_cache_module, match);
/* shortcircuit the get_path_info() stat() calls and stuff */
return OK;
}
-
static int mmap_handler(request_rec *r, a_file *file)
{
#if APR_HAS_MMAP
static command_rec file_cache_cmds[] =
{
-AP_INIT_ITERATE("cachefile", cachefile, NULL, RSRC_CONF,
+AP_INIT_ITERATE("cachefile", cachefilehandle, NULL, RSRC_CONF,
"A space separated list of files to add to the file handle cache at config time"),
-AP_INIT_ITERATE("mmapfile", mmapfile, NULL, RSRC_CONF,
+AP_INIT_ITERATE("mmapfile", cachefilemmap, NULL, RSRC_CONF,
"A space separated list of files to mmap at config time"),
{NULL}
};