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 */

Reply via email to