r15183: Hoist the critical sizes initialiser into a header so that modules
[gd/samba/.git] / source4 / ntvfs / ntvfs_base.c
index 11f39c5d593a25a384420ec85093b051a170042b..1705bbef2ffc9aee76b5e535c30ffe8baf04a7c5 100644 (file)
@@ -1,7 +1,9 @@
 /* 
    Unix SMB/CIFS implementation.
    NTVFS base code
+
    Copyright (C) Andrew Tridgell 2003
+   Copyright (C) Stefan (metze) Metzmacher 2004
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 */
 
 #include "includes.h"
-
+#include "dlinklist.h"
+#include "build.h"
+#include "ntvfs/ntvfs.h"
 
 /* the list of currently registered NTVFS backends, note that there
  * can be more than one backend with the same name, as long as they
  * have different typesx */
-static struct {
-       struct ntvfs_ops *ops;
+static struct ntvfs_backend {
+       const struct ntvfs_ops *ops;
 } *backends = NULL;
 static int num_backends;
 
@@ -40,27 +44,33 @@ static int num_backends;
 
   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
 */
-static NTSTATUS ntvfs_register(void *_ops)
+_PUBLIC_ NTSTATUS ntvfs_register(const void *_ops)
 {
-       struct ntvfs_ops *ops = _ops;
+       const struct ntvfs_ops *ops = _ops;
+       struct ntvfs_ops *new_ops;
        
        if (ntvfs_backend_byname(ops->name, ops->type) != NULL) {
                /* its already registered! */
-               DEBUG(2,("NTVFS backend '%s' for type %d already registered\n", 
+               DEBUG(0,("NTVFS backend '%s' for type %d already registered\n", 
                         ops->name, (int)ops->type));
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       backends = Realloc(backends, sizeof(backends[0]) * (num_backends+1));
+       backends = realloc_p(backends, struct ntvfs_backend, num_backends+1);
        if (!backends) {
                smb_panic("out of memory in ntvfs_register");
        }
 
-       backends[num_backends].ops = smb_xmemdup(ops, sizeof(*ops));
-       backends[num_backends].ops->name = smb_xstrdup(ops->name);
+       new_ops = smb_xmemdup(ops, sizeof(*ops));
+       new_ops->name = smb_xstrdup(ops->name);
+
+       backends[num_backends].ops = new_ops;
 
        num_backends++;
 
+       DEBUG(3,("NTVFS backend '%s' for type %d registered\n", 
+                ops->name,ops->type));
+
        return NT_STATUS_OK;
 }
 
@@ -68,7 +78,7 @@ static NTSTATUS ntvfs_register(void *_ops)
 /*
   return the operations structure for a named backend of the specified type
 */
-struct ntvfs_ops *ntvfs_backend_byname(const char *name, enum ntvfs_type type)
+_PUBLIC_ const struct ntvfs_ops *ntvfs_backend_byname(const char *name, enum ntvfs_type type)
 {
        int i;
 
@@ -88,48 +98,108 @@ struct ntvfs_ops *ntvfs_backend_byname(const char *name, enum ntvfs_type type)
   This can be used by backends to either detect compilation errors, or provide
   multiple implementations for different smbd compilation options in one module
 */
-int ntvfs_interface_version(struct ntvfs_critical_sizes *sizes)
-{
-       sizes->sizeof_ntvfs_ops = sizeof(struct ntvfs_ops);
-       sizes->sizeof_SMB_OFF_T = sizeof(SMB_OFF_T);
-       sizes->sizeof_tcon_context = sizeof(struct tcon_context);
-       sizes->sizeof_request_context = sizeof(struct request_context);
 
-       return NTVFS_INTERFACE_VERSION;
-}
+static const NTVFS_CURRENT_CRITICAL_SIZES(critical_sizes);
 
+_PUBLIC_ const struct ntvfs_critical_sizes *ntvfs_interface_version(void)
+{
+       return &critical_sizes;
+}
 
-/*
-  initialise the NTVFS subsystem
-*/
-BOOL ntvfs_init(void)
+_PUBLIC_ BOOL ntvfs_interface_differs(const struct ntvfs_critical_sizes *const iface)
 {
-       register_subsystem("ntvfs", ntvfs_register); 
+       /* The comparison would be easier with memcmp, but compiler-interset
+        * alignment padding is not guaranteed to be zeroed.
+        */
+
+#define FIELD_DIFFERS(field) (iface->field != critical_sizes.field)
+
+       if (FIELD_DIFFERS(interface_version))
+               return True;
+
+       if (FIELD_DIFFERS(sizeof_ntvfs_critical_sizes))
+               return True;
+
+       if (FIELD_DIFFERS(sizeof_ntvfs_context))
+               return True;
+
+       if (FIELD_DIFFERS(sizeof_ntvfs_module_context))
+               return True;
+
+       if (FIELD_DIFFERS(sizeof_ntvfs_ops))
+               return True;
 
-       /* FIXME: Perhaps panic if a basic backend, such as IPC, fails to initialise? */
-       static_init_ntvfs;
+       if (FIELD_DIFFERS(sizeof_ntvfs_async_state))
+               return True;
 
-       DEBUG(3,("NTVFS version %d initialised\n", NTVFS_INTERFACE_VERSION));
-       return True;
+       if (FIELD_DIFFERS(sizeof_ntvfs_request))
+               return True;
+
+       /* Versions match. */
+       return False;
+
+#undef FIELD_DIFFERS
 }
 
 
 /*
   initialise a connection structure to point at a NTVFS backend
 */
-NTSTATUS ntvfs_init_connection(struct request_context *req)
+NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, int snum, enum ntvfs_type type,
+                              enum protocol_types protocol,
+                              struct event_context *ev, struct messaging_context *msg,
+                              uint32_t server_id, struct ntvfs_context **_ctx)
 {
-       const char *handler = lp_ntvfs_handler(req->conn->service);
-       
-       if (strequal(handler, "default"))
-               handler = "ipc";
+       const char **handlers = lp_ntvfs_handler(snum);
+       int i;
+       struct ntvfs_context *ctx;
 
-       req->conn->ntvfs_ops = ntvfs_backend_byname(handler, req->conn->type);
+       if (!handlers) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       ctx = talloc_zero(mem_ctx, struct ntvfs_context);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+       ctx->protocol           = protocol;
+       ctx->type               = type;
+       ctx->config.snum        = snum;
+       ctx->event_ctx          = ev;
+       ctx->msg_ctx            = msg;
+       ctx->server_id          = server_id;
+
+       for (i=0; handlers[i]; i++) {
+               struct ntvfs_module_context *ntvfs;
+
+               ntvfs = talloc_zero(ctx, struct ntvfs_module_context);
+               NT_STATUS_HAVE_NO_MEMORY(ntvfs);
+               ntvfs->ctx = ctx;
+               ntvfs->ops = ntvfs_backend_byname(handlers[i], ctx->type);
+               if (!ntvfs->ops) {
+                       DEBUG(1,("ntvfs_init_connection: failed to find backend=%s, type=%d\n",
+                               handlers[i], ctx->type));
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+               ntvfs->depth = i;
+               DLIST_ADD_END(ctx->modules, ntvfs, struct ntvfs_module_context *);
+       }
 
-       if (!req->conn->ntvfs_ops) {
-               DEBUG(1,("ntvfs_init_connection: failed to find backend=%s, type=%d\n", handler, req->conn->type));
-               return NT_STATUS_UNSUCCESSFUL;
+       if (!ctx->modules) {
+               return NT_STATUS_INTERNAL_ERROR;
        }
 
+       *_ctx = ctx;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS ntvfs_init(void)
+{
+       init_module_fn static_init[] = STATIC_ntvfs_MODULES;
+       init_module_fn *shared_init = load_samba_modules(NULL, "ntvfs");
+
+       run_init_functions(static_init);
+       run_init_functions(shared_init);
+
+       talloc_free(shared_init);
+       
        return NT_STATUS_OK;
 }