Attached is a proof of concept for an Apache VFS layer.
There is a consumer API which just mimics the APR file IO API with
the addition of a request_rec *r argument (see example patch to
consumer code).
There is a provider interface using an ap_vfs_mount structure that
can be filled out and there is a default implementation that directly
delegates to the APR file IO routines.
It could probably be cleaned up a little with some helper macros
to reduce the duplication in the interface definitions.
I have not yet considered a mounting/stacking API - there is a very
simple get_mount implementation that allows me to test this for stacking
by exporting a list head (I have my mod_privsep working against this).
Index: server/core.c
===================================================================
--- server/core.c (revision 604779)
+++ server/core.c (working copy)
@@ -49,6 +49,7 @@
#include "mod_core.h"
#include "mod_proxy.h"
#include "ap_listen.h"
+#include "ap_vfs.h"
#include "mod_so.h" /* for ap_find_loaded_module_symbol */
@@ -3600,7 +3601,7 @@
}
- if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
+ if ((status = ap_vfs_file_open(r, &fd, r->filename, APR_READ |
APR_BINARY
#if APR_HAS_SENDFILE
| ((d->enable_sendfile == ENABLE_SENDFILE_OFF)
? 0 : APR_SENDFILE_ENABLED)
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file ap_vfs.h
* @brief Virtual File System interface
*
* @defgroup APACHE_CORE_VFS Virtual File System interface
* @ingroup APACHE_CORE
* @{
*/
#ifndef APACHE_VFS_H
#define APACHE_VFS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "apr.h"
#include "apr_file_io.h"
#include "httpd.h"
#define AP_USE_VFS 1
#if !AP_USE_VFS
/* VFS Interface disabled */
#define ap_vfs_stat(r, finfo, fname, wanted, pool) \
apr_stat(finfo, fname, wanted, pool)
#define ap_vfs_file_open(r, new, fname, flag, perm, pool) \
apr_file_open(new, fname, flag, perm, pool)
#define ap_vfs_file_remove(r, path, pool) \
apr_file_remove(path, pool)
#define ap_vfs_file_rename(r, from_path, to_path, p) \
apr_file_rename(from_path, to_path, p)
#define ap_vfs_file_perms_set(r, fname, perms) \
apr_file_perms_set(fname, perms)
#define ap_vfs_dir_open(r, new, dirname, pool) \
apr_dir_open(new, dirname, pool)
#define ap_vfs_dir_read(r, finfo, wanted, thedir) \
apr_dir_read(finfo, wanted, thedir)
#define ap_vfs_dir_make(r, path, perm, pool) \
apr_dir_make(path, perm, pool)
#define ap_vfs_dir_remove(r, path, pool) \
apr_dir_remove(path, pool)
#else
/* VFS Interface */
AP_DECLARE(apr_status_t) ap_vfs_stat(const request_rec *r,
apr_finfo_t *finfo,
const char *fname,
apr_int32_t wanted,
apr_pool_t *pool);
AP_DECLARE(apr_status_t) ap_vfs_file_open(const request_rec *r,
apr_file_t **new,
const char *fname,
apr_int32_t flag,
apr_fileperms_t perm,
apr_pool_t *pool);
AP_DECLARE(apr_status_t) ap_vfs_file_remove(const request_rec *r,
const char *path,
apr_pool_t *pool);
AP_DECLARE(apr_status_t) ap_vfs_file_rename(const request_rec *r,
const char *from_path,
const char *to_path,
apr_pool_t *p);
AP_DECLARE(apr_status_t) ap_vfs_file_perms_set(const request_rec *r,
const char *fname,
apr_fileperms_t perms);
AP_DECLARE(apr_status_t) ap_vfs_dir_open(const request_rec *r,
apr_dir_t **new,
const char *dirname,
apr_pool_t *pool);
AP_DECLARE(apr_status_t) ap_vfs_dir_read(const request_rec *r,
apr_finfo_t *finfo,
apr_int32_t wanted,
apr_dir_t *thedir);
AP_DECLARE(apr_status_t) ap_vfs_dir_make(const request_rec *r,
const char *path,
apr_fileperms_t perm,
apr_pool_t *pool);
AP_DECLARE(apr_status_t) ap_vfs_dir_remove(const request_rec *r,
const char *path,
apr_pool_t *pool);
/* VFS function typedefs for ap_vfs_mount providers */
typedef struct ap_vfs_mount ap_vfs_mount;
typedef apr_status_t (ap_vfs_stat_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
apr_finfo_t *finfo,
const char *fname,
apr_int32_t wanted,
apr_pool_t *pool);
typedef apr_status_t (ap_vfs_file_open_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
apr_file_t **new,
const char *fname,
apr_int32_t flag,
apr_fileperms_t perm,
apr_pool_t *pool);
typedef apr_status_t (ap_vfs_file_remove_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
const char *path,
apr_pool_t *pool);
typedef apr_status_t (ap_vfs_file_rename_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
const char *from_path,
const char *to_path,
apr_pool_t *p);
typedef apr_status_t (ap_vfs_file_perms_set_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
const char *fname,
apr_fileperms_t perms);
typedef apr_status_t (ap_vfs_dir_open_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
apr_dir_t **new,
const char *dirname,
apr_pool_t *pool);
typedef apr_status_t (ap_vfs_dir_read_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
apr_finfo_t *finfo,
apr_int32_t wanted,
apr_dir_t *thedir);
typedef apr_status_t (ap_vfs_dir_make_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
const char *path,
apr_fileperms_t perm,
apr_pool_t *pool);
typedef apr_status_t (ap_vfs_dir_remove_fn)(const ap_vfs_mount *mnt,
const request_rec *r,
const char *path,
apr_pool_t *pool);
/* VFS Mount provider structure */
struct ap_vfs_mount {
ap_vfs_mount *next;
void *userdata;
/* VFS implementation hooks */
ap_vfs_stat_fn *stat;
ap_vfs_file_open_fn *file_open;
ap_vfs_file_remove_fn *file_remove;
ap_vfs_file_rename_fn *file_rename;
ap_vfs_file_perms_set_fn *file_perms_set;
ap_vfs_dir_open_fn *dir_open;
ap_vfs_dir_read_fn *dir_read;
ap_vfs_dir_make_fn *dir_make;
ap_vfs_dir_remove_fn *dir_remove;
};
/* linked list of ap_vfs_mount structures */
extern ap_vfs_mount *ap_vfs_mount_head;
#endif /* AP_USE_VFS */
#endif /* APACHE_VFS_H */
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "apr.h"
#include "apr_file_io.h"
#include "ap_vfs.h"
#if AP_USE_VFS
/* forward declaration of find_mount used by vfs interface functions */
static const ap_vfs_mount* find_mount(const request_rec *r,
const char *pathname);
/*
* VFS interface functions
*/
APR_DECLARE(apr_status_t) ap_vfs_stat(const request_rec *r,
apr_finfo_t *finfo,
const char *fname,
apr_int32_t wanted,
apr_pool_t *pool)
{
const ap_vfs_mount *mnt = find_mount(r, fname);
return mnt->stat(mnt, r, finfo, fname, wanted, pool);
}
APR_DECLARE(apr_status_t) ap_vfs_file_open(const request_rec *r,
apr_file_t **new,
const char *fname,
apr_int32_t flag,
apr_fileperms_t perm,
apr_pool_t *pool)
{
const ap_vfs_mount *mnt = find_mount(r, fname);
return mnt->file_open(mnt, r, new, fname, flag, perm, pool);
}
APR_DECLARE(apr_status_t) ap_vfs_file_remove(const request_rec *r,
const char *path,
apr_pool_t *pool)
{
const ap_vfs_mount *mnt = find_mount(r, path);
return mnt->file_remove(mnt, r, path, pool);
}
APR_DECLARE(apr_status_t) ap_vfs_file_rename(const request_rec *r,
const char *from_path,
const char *to_path,
apr_pool_t *p)
{
const ap_vfs_mount *from_mnt = find_mount(r, from_path);
const ap_vfs_mount *to_mnt = find_mount(r, to_path);
if(from_mnt == to_mnt) {
return from_mnt->file_rename(from_mnt, r, from_path, to_path, p);
}
else {
/* rename across mount mounts not possible */
return APR_EXDEV;
}
}
APR_DECLARE(apr_status_t) ap_vfs_file_perms_set(const request_rec *r,
const char *fname,
apr_fileperms_t perms)
{
const ap_vfs_mount *mnt = find_mount(r, fname);
return mnt->file_perms_set(mnt, r, fname, perms);
}
APR_DECLARE(apr_status_t) ap_vfs_dir_open(const request_rec *r,
apr_dir_t **new,
const char *dirname,
apr_pool_t *pool)
{
const ap_vfs_mount *mnt = find_mount(r, dirname);
return mnt->dir_open(mnt, r, new, dirname, pool);
}
APR_DECLARE(apr_status_t) ap_vfs_dir_read(const request_rec *r,
apr_finfo_t *finfo,
apr_int32_t wanted,
apr_dir_t *thedir)
{
char* dirname;
const ap_vfs_mount *mnt;
/* This requires a new APR interface to get the dirname of the dir.
The version below uses Iain Wade's APR patches which could perhaps
be simplified to:
const char * apr_dir_name_get(apr_dir_t *thedir)
*/
apr_dir_name_get(&dirname, thedir);
mnt = find_mount(r, dirname);
return mnt->dir_read(mnt, r, finfo, wanted, thedir);
}
APR_DECLARE(apr_status_t) ap_vfs_dir_make(const request_rec *r,
const char *path,
apr_fileperms_t perm,
apr_pool_t *pool)
{
const ap_vfs_mount *mnt = find_mount(r, path);
return mnt->dir_make(mnt, r, path, perm, pool);
}
APR_DECLARE(apr_status_t) ap_vfs_dir_remove(const request_rec *r,
const char *path,
apr_pool_t *pool)
{
const ap_vfs_mount *mnt = find_mount(r, path);
return mnt->dir_remove(mnt, r, path, pool);
}
/*
* Default APR VFS implementation
*/
static apr_status_t vfs_apr_stat(const ap_vfs_mount *mnt,
const request_rec *r,
apr_finfo_t *finfo,
const char *fname,
apr_int32_t wanted,
apr_pool_t *pool)
{
return apr_stat(finfo, fname, wanted, pool);
}
static apr_status_t vfs_apr_file_open(const ap_vfs_mount *mnt,
const request_rec *r,
apr_file_t **new,
const char *fname,
apr_int32_t flag,
apr_fileperms_t perm,
apr_pool_t *pool)
{
return apr_file_open(new, fname, flag, perm, pool);
}
static apr_status_t vfs_apr_file_remove(const ap_vfs_mount *mnt,
const request_rec *r,
const char *path,
apr_pool_t *pool)
{
return apr_file_remove(path, pool);
}
static apr_status_t vfs_apr_file_rename(const ap_vfs_mount *mnt,
const request_rec *r,
const char *from_path,
const char *to_path,
apr_pool_t *p)
{
return apr_file_rename(from_path, to_path, p);
}
static apr_status_t vfs_apr_file_perms_set(const ap_vfs_mount *mnt,
const request_rec *r,
const char *fname,
apr_fileperms_t perms)
{
return apr_file_perms_set(fname, perms);
}
static apr_status_t vfs_apr_dir_open(const ap_vfs_mount *mnt,
const request_rec *r,
apr_dir_t **new,
const char *dirname,
apr_pool_t *pool)
{
return apr_dir_open(new, dirname, pool);
}
static apr_status_t vfs_apr_dir_read(const ap_vfs_mount *mnt,
const request_rec *r,
apr_finfo_t *finfo,
apr_int32_t wanted,
apr_dir_t *thedir)
{
return apr_dir_read(finfo, wanted, thedir);
}
static apr_status_t vfs_apr_dir_make(const ap_vfs_mount *mnt,
const request_rec *r,
const char *path,
apr_fileperms_t perm,
apr_pool_t *pool)
{
return apr_dir_make(path, perm, pool);
}
static apr_status_t vfs_apr_dir_remove(const ap_vfs_mount *mnt,
const request_rec *r,
const char *path,
apr_pool_t *pool)
{
return apr_dir_remove(path, pool);
}
/*
* Root VFS mount
*/
static ap_vfs_mount root_vfs_mount = {
NULL,
NULL,
vfs_apr_stat,
vfs_apr_file_open,
vfs_apr_file_remove,
vfs_apr_file_rename,
vfs_apr_file_perms_set,
vfs_apr_dir_open,
vfs_apr_dir_read,
vfs_apr_dir_make,
vfs_apr_dir_remove
};
ap_vfs_mount *ap_vfs_mount_head = &root_vfs_mount;
/*
* locates the mount structure for the provided path name
*/
static const ap_vfs_mount* find_mount(const request_rec *r,
const char *pathname)
{
/* Proof-of-concept implementation that doesn't yet handle
mount points but is enough to enable stacking */
return ap_vfs_mount_head;
}
#endif /* AP_USE_VFS */