Michael Clark wrote:
Attached is a proof of concept for an Apache VFS layer.
Hope you don't mind me thinking aloud.... ( I know most of you are having holidays now so I'm not expecting any detailed feedback yet :) )

There were certain glaringly obvious flaws in what I had posted earlier - it wasn't enough to provide a fully virtualised VFS - only enough for mod_privsep.

I have attached a revised header that should address (some of) these issues (after sleeping on it).

* adds vfs_file_t and vfs_dir_t types (apr_finfo_t can still be used in the interfaces as it is not opaque and I don't think it makes sense to duplicate this) * adds file_read, file_write, file_eof, file_close, file_seek, dir_close interfaces (and more interfaces will be needed, file_copy, file_lock, file_unlock, ...)

This should be close to enough to allow implementations that are not just stacked on top of APR file IO (like mod_privsep).

I'm going to have a go with implementations based on this interface over the next few weeks (and add whatever other interfaces are needed). It will all be done in such a way that the VFS could be switched off completely with #defines pointing directly at the APR file io functions.

I was thinking (based on Paul's earlier comments) of adding a vfs_iocb (IO callback) argument to all of the interfaces which could be NULL for synchronous IO (and if existing synchronous code was changed to use this interface then it would just pass NULL).

This vfs_iocb interface could then be documented such that an implementation that does not provide async operation may call the vfs_iocb callback before returning. Then the default implementation on top of APR could do this. Later an async implementation could be written that uses IO worker threads (and we would specify that the iocb could be called in another thread to that which submitted the op).

There are some encapsulation boundary issues also, apr_dbm_open comes to mind. Not sure how to handle this (one reason why I want to have an mod_dav_fs_props_xattr).

Anyway, I'll report back on my experiments...

Have a happy Chirstmas Eve.
Cheers, Michael.

/* 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 vfs_file_t apr_file_t
#define vfs_dir_t apr_dir_t

#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_read(thefile, buf, nbytes) \
    apr_file_read(thefile, buf, nbytes)
#define ap_vfs_file_write(thefile, buf, nbytes) \
    apr_file_write(thefile, buf, nbytes)
#define ap_vfs_file_seek(thefile, where, offset) \
    apr_file_seek(thefile, where, offset)
#define ap_vfs_file_eof(thefile) \
    apr_file_eof(thefile)
#define ap_vfs_file_close(thefile) \
    apr_file_close(thefile)
#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(finfo, wanted, thedir) \
    apr_dir_read(finfo, wanted, thedir)
#define ap_vfs_dir_close(thedir) \
    apr_dir_close(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 Public Interface */

typedef struct vfs_file_t vfs_file_t;
typedef struct vfs_dir_t vfs_dir_t;
typedef struct vfs_mount vfs_mount;

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,
                                          vfs_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_read(vfs_file_t *thefile,
					  void *buf,
					  apr_size_t *nbytes);

AP_DECLARE(apr_status_t) ap_vfs_file_write(vfs_file_t *thefile,
					   const void *buf,
					   apr_size_t *nbytes);

AP_DECLARE(apr_status_t) ap_vfs_file_seek(vfs_file_t *thefile, 
					  apr_seek_where_t where,
					  apr_off_t *offset);

AP_DECLARE(apr_status_t) ap_vfs_file_eof(vfs_file_t *file);

AP_DECLARE(apr_status_t) ap_vfs_file_close(vfs_file_t *file);

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,
                                         vfs_dir_t **new,
                                         const char *dirname, 
                                         apr_pool_t *pool);

AP_DECLARE(apr_status_t) ap_vfs_dir_read(apr_finfo_t *finfo,
                                         apr_int32_t wanted,
                                         vfs_dir_t *thedir);

AP_DECLARE(apr_status_t) ap_vfs_dir_close(vfs_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 Provider interface */

struct vfs_mount {
    vfs_mount     *next;
    apr_uint32_t  flags;
    const char    *mountpoint;
    void          *userdata;

    /* VFS implementation hooks */
    apr_status_t (*stat)          (const vfs_mount *mnt, const request_rec *r,
				   apr_finfo_t *finfo, const char *fname, 
				   apr_int32_t wanted, apr_pool_t *pool);
    apr_status_t (*file_open)     (const vfs_mount *mnt, const request_rec *r,
				   vfs_file_t **new,  const char *fname, 
				   apr_int32_t flag,  apr_fileperms_t perm, 
				   apr_pool_t *pool);
    apr_status_t (*file_read)     (const vfs_mount *mnt, vfs_file_t *thefile,
				   void *buf, apr_size_t *nbytes);
    apr_status_t (*file_write)    (const vfs_mount *mnt, vfs_file_t *thefile,
				   const void *buf, apr_size_t *nbytes);
    apr_status_t (*file_seek)     (const vfs_mount *mnt, vfs_file_t *thefile, 
				   apr_seek_where_t where, apr_off_t *offset);
    apr_status_t (*file_eof)      (const vfs_mount *mnt, vfs_file_t *file);
    apr_status_t (*file_close)    (const vfs_mount *mnt, vfs_file_t *file);
    apr_status_t (*file_remove)   (const vfs_mount *mnt, const request_rec *r,
				   const char *path, apr_pool_t *pool);
    apr_status_t (*file_rename)   (const vfs_mount *mnt, const request_rec *r,
				   const char *from_path, const char *to_path,
				   apr_pool_t *p);
    apr_status_t (*file_perms_set)(const vfs_mount *mnt, const request_rec *r,
				   const char *fname,  apr_fileperms_t perms);
    apr_status_t (*dir_open)      (const vfs_mount *mnt, const request_rec *r,
				   vfs_dir_t **new, const char *dirname, 
				   apr_pool_t *pool);
    apr_status_t (*dir_read)      (const vfs_mount *mnt, apr_finfo_t *finfo,
				   apr_int32_t wanted, vfs_dir_t *thedir);
    apr_status_t (*dir_close)     (const vfs_mount *mnt, vfs_dir_t *thedir);
    apr_status_t (*dir_make)      (const vfs_mount *mnt, const request_rec *r,
				   const char *path, apr_fileperms_t perm, 
				   apr_pool_t *pool);
    apr_status_t (*dir_remove)    (const vfs_mount *mnt, const request_rec *r,
				   const char *path, apr_pool_t *pool);
};

/* VFS file type */

struct vfs_file_t {
    vfs_mount    *mnt;
    void         *userdata;
};

/* VFS directory type */

struct vfs_dir_t {
    vfs_mount    *mnt;
    void         *userdata;
};

/* linked list of vfs_mount structures */

extern vfs_mount *ap_vfs_mount_head;

#endif /* AP_USE_VFS */

#endif /* APACHE_VFS_H */

Reply via email to