r15184: Declare ntvfs_register with a typed ops pointer.
[samba.git] / source4 / ntvfs / ntvfs_base.c
1 /* 
2    Unix SMB/CIFS implementation.
3    NTVFS base code
4
5    Copyright (C) Andrew Tridgell 2003
6    Copyright (C) Stefan (metze) Metzmacher 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /*
23   this implements the core code for all NTVFS modules. Backends register themselves here.
24 */
25
26 #include "includes.h"
27 #include "dlinklist.h"
28 #include "build.h"
29 #include "ntvfs/ntvfs.h"
30
31 /* the list of currently registered NTVFS backends, note that there
32  * can be more than one backend with the same name, as long as they
33  * have different typesx */
34 static struct ntvfs_backend {
35         const struct ntvfs_ops *ops;
36 } *backends = NULL;
37 static int num_backends;
38
39 /*
40   register a NTVFS backend. 
41
42   The 'name' can be later used by other backends to find the operations
43   structure for this backend.  
44
45   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
46 */
47 _PUBLIC_ NTSTATUS ntvfs_register(const struct ntvfs_ops *ops)
48 {
49         struct ntvfs_ops *new_ops;
50         
51         if (ntvfs_backend_byname(ops->name, ops->type) != NULL) {
52                 /* its already registered! */
53                 DEBUG(0,("NTVFS backend '%s' for type %d already registered\n", 
54                          ops->name, (int)ops->type));
55                 return NT_STATUS_OBJECT_NAME_COLLISION;
56         }
57
58         backends = realloc_p(backends, struct ntvfs_backend, num_backends+1);
59         if (!backends) {
60                 smb_panic("out of memory in ntvfs_register");
61         }
62
63         new_ops = smb_xmemdup(ops, sizeof(*ops));
64         new_ops->name = smb_xstrdup(ops->name);
65
66         backends[num_backends].ops = new_ops;
67
68         num_backends++;
69
70         DEBUG(3,("NTVFS backend '%s' for type %d registered\n", 
71                  ops->name,ops->type));
72
73         return NT_STATUS_OK;
74 }
75
76
77 /*
78   return the operations structure for a named backend of the specified type
79 */
80 _PUBLIC_ const struct ntvfs_ops *ntvfs_backend_byname(const char *name, enum ntvfs_type type)
81 {
82         int i;
83
84         for (i=0;i<num_backends;i++) {
85                 if (backends[i].ops->type == type && 
86                     strcmp(backends[i].ops->name, name) == 0) {
87                         return backends[i].ops;
88                 }
89         }
90
91         return NULL;
92 }
93
94
95 /*
96   return the NTVFS interface version, and the size of some critical types
97   This can be used by backends to either detect compilation errors, or provide
98   multiple implementations for different smbd compilation options in one module
99 */
100
101 static const NTVFS_CURRENT_CRITICAL_SIZES(critical_sizes);
102
103 _PUBLIC_ const struct ntvfs_critical_sizes *ntvfs_interface_version(void)
104 {
105         return &critical_sizes;
106 }
107
108 _PUBLIC_ BOOL ntvfs_interface_differs(const struct ntvfs_critical_sizes *const iface)
109 {
110         /* The comparison would be easier with memcmp, but compiler-interset
111          * alignment padding is not guaranteed to be zeroed.
112          */
113
114 #define FIELD_DIFFERS(field) (iface->field != critical_sizes.field)
115
116         if (FIELD_DIFFERS(interface_version))
117                 return True;
118
119         if (FIELD_DIFFERS(sizeof_ntvfs_critical_sizes))
120                 return True;
121
122         if (FIELD_DIFFERS(sizeof_ntvfs_context))
123                 return True;
124
125         if (FIELD_DIFFERS(sizeof_ntvfs_module_context))
126                 return True;
127
128         if (FIELD_DIFFERS(sizeof_ntvfs_ops))
129                 return True;
130
131         if (FIELD_DIFFERS(sizeof_ntvfs_async_state))
132                 return True;
133
134         if (FIELD_DIFFERS(sizeof_ntvfs_request))
135                 return True;
136
137         /* Versions match. */
138         return False;
139
140 #undef FIELD_DIFFERS
141 }
142
143
144 /*
145   initialise a connection structure to point at a NTVFS backend
146 */
147 NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, int snum, enum ntvfs_type type,
148                                enum protocol_types protocol,
149                                struct event_context *ev, struct messaging_context *msg,
150                                uint32_t server_id, struct ntvfs_context **_ctx)
151 {
152         const char **handlers = lp_ntvfs_handler(snum);
153         int i;
154         struct ntvfs_context *ctx;
155
156         if (!handlers) {
157                 return NT_STATUS_INTERNAL_ERROR;
158         }
159
160         ctx = talloc_zero(mem_ctx, struct ntvfs_context);
161         NT_STATUS_HAVE_NO_MEMORY(ctx);
162         ctx->protocol           = protocol;
163         ctx->type               = type;
164         ctx->config.snum        = snum;
165         ctx->event_ctx          = ev;
166         ctx->msg_ctx            = msg;
167         ctx->server_id          = server_id;
168
169         for (i=0; handlers[i]; i++) {
170                 struct ntvfs_module_context *ntvfs;
171
172                 ntvfs = talloc_zero(ctx, struct ntvfs_module_context);
173                 NT_STATUS_HAVE_NO_MEMORY(ntvfs);
174                 ntvfs->ctx = ctx;
175                 ntvfs->ops = ntvfs_backend_byname(handlers[i], ctx->type);
176                 if (!ntvfs->ops) {
177                         DEBUG(1,("ntvfs_init_connection: failed to find backend=%s, type=%d\n",
178                                 handlers[i], ctx->type));
179                         return NT_STATUS_INTERNAL_ERROR;
180                 }
181                 ntvfs->depth = i;
182                 DLIST_ADD_END(ctx->modules, ntvfs, struct ntvfs_module_context *);
183         }
184
185         if (!ctx->modules) {
186                 return NT_STATUS_INTERNAL_ERROR;
187         }
188
189         *_ctx = ctx;
190         return NT_STATUS_OK;
191 }
192
193 NTSTATUS ntvfs_init(void)
194 {
195         init_module_fn static_init[] = STATIC_ntvfs_MODULES;
196         init_module_fn *shared_init = load_samba_modules(NULL, "ntvfs");
197
198         run_init_functions(static_init);
199         run_init_functions(shared_init);
200
201         talloc_free(shared_init);
202         
203         return NT_STATUS_OK;
204 }