1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE book PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
<chapter id="registry">
<chapterinfo>
&author.jelmer;
<pubdate>24 September 2003</pubdate>
</chapterinfo>
<title>The registry subsystem</title>
<sect1><title>Planned backends</title>
<para>
The new registry subsystem will work with several different backends:
</para>
<itemizedlist>
<listitem><para>NT4 (NT4 registry files)</para></listitem>
<listitem><para>TDB (Samba TDB files)</para></listitem>
<listitem><para>RPC (Remote Registry over RPC, reg pipe)</para></listitem>
<listitem><para>wine (Wine Registry Files)</para></listitem>
<listitem><para>gconf (The GNOME configuration backend)</para></listitem>
</itemizedlist>
</sect1>
<sect1><title>Data structures</title>
<para>
The following structure describes a registry key:
</para>
<programlisting>
typedef struct reg_key_s {
char *name; /* Name of the key */
smb_ucs2_t *class_name; /* Name of key class */
int type; /* One of REG_ROOT_KEY or REG_SUB_KEY */
NTTIME last_mod; /* Time last modified */
struct reg_key_s *owner;
struct key_list_s *sub_keys; /* NULL indicates keys not available in memory, function should be called */
struct val_list_s *values; /* NULL indicates values not available in memory, function should be called */
SEC_DESC *security;
REG_HANDLE *handle; /* Pointer to REG_HANDLE this key belongs to */
void *backend_data; /* Pointer used by the backend */
} REG_KEY;
</programlisting>
<para>The following structure describes a registry value:</para>
<programlisting>
typedef struct val_key_s {
char *name; /* NULL if name not available */
int data_type;
int data_len;
void *data_blk; /* Might want a separate block */
REG_HANDLE *handle; /* Pointer to REG_HANDLE this key belongs to */
void *backend_data;
} REG_VAL;
</programlisting>
<para>The following structures are used for lists of subkeys or values:</para>
<programlisting>
/* container for registry subkey names */
typedef struct key_list_s {
TALLOC_CTX *ctx;
uint32 num_subkeys;
REG_KEY **subkeys;
} REG_KEY_LIST;
/* container for registry values */
typedef struct val_list_s {
TALLOC_CTX *ctx;
uint32 num_vals;
REG_VAL **vals;
} REG_VAL_LIST;
</programlisting>
<para>
And this structure is used for an instance of a registry (a registry file that's opened, a remote registry pipe we're connected to, etc).
</para>
<programlisting>
typedef struct reg_handle_s {
REGISTRY_OPS *functions;
REG_KEY *root; /* NULL if not available */
void *backend_data;
} REG_HANDLE;
</programlisting>
</sect1>
<sect1>
<title>External interface</title>
<programlisting>
REG_HANDLE *reg_open(char *backend, char *location, BOOL try_full_load);
REG_KEY *reg_open_key(REG_KEY *parent, char *name);
REG_VAL *reg_key_get_val(REG_KEY *key, char *name);
REG_VAL_LIST *reg_key_get_vals(REG_KEY *key);
REG_KEY_LIST *reg_key_get_subkeys(REG_KEY *key);
BOOL reg_key_del(REG_KEY *key);
BOOL reg_val_del(REG_VAL *val);
BOOL reg_key_add(REG_KEY *parent, REG_KEY *key);
BOOL reg_val_add(REG_KEY *parent, REG_VAL *val):
BOOL reg_val_update(REG_VAL *val);
BOOL reg_key_update(REG_KEY *key);
void reg_free_key(REG_KEY *key);
void reg_free_val(REG_VAL *val);
void reg_free(REG_HANDLE *h);
void reg_free_key_list(REG_KEY_LIST *list):
void reg_free_val_list(REG_VAL_LIST *list):
</programlisting>
</sect1>
<sect1>
<title>Utility functions</title>
<para>The following helper functions are available:</para>
<programlisting>
void reg_key_list_init( REG_KEY_LIST *ctr );
int reg_key_list_addkey( REG_KEY_LIST *ctr, const char *keyname );
int reg_key_list_numkeys( REG_KEY_LIST *ctr );
char* reg_key_list_specific_key( REG_KEY_LIST *ctr, uint32 key_index );
void reg_key_list_destroy( REG_KEY_LIST *ctr );
void reg_val_list_init( REG_VAL_LIST *ctr );
int reg_val_list_numvals( REG_VAL_LIST *ctr );
void free_registry_value( REG_VAL *val );
uint8* regval_data_p( REG_VAL *val );
int regval_size( REG_VAL *val );
char* regval_name( REG_VAL *val );
uint32 regval_type( REG_VAL *val );
TALLOC_CTX* reg_val_list_getctx( REG_VAL_LIST *val );
int reg_val_list_addvalue( REG_VAL_LIST *ctr, const char *name, uint16 type,
const char *data_p, size_t size );
int reg_val_list_copyvalue( REG_VAL_LIST *ctr, REG_VAL *val );
int reg_val_list_delvalue( REG_VAL_LIST *ctr, const char *name );
void reg_val_list_destroy( REG_VAL_LIST *ctr );
</programlisting>
</sect1>
<sect1>
<title>Writing backends</title>
<para>There are basically two ways of reading data from the registry: loading
it all into memory and then working in this copy in memory, or
re-reading/re-opening it every time necessary.</para>
<para>This interface aims to support both types. </para>
<para>A registry backend should provide the following functions:</para>
<programlisting>
typedef struct {
REG_HANDLE *(*open_registry) (const char *location, BOOL try_complete_load);
REG_KEY *(*open_root_key) (REG_HANDLE *);
REG_KEY *(*open_key_rel) (REG_KEY *parent, const char *name);
/* if open_key_abs is set to NULL, a default implementation will be provided. */
REG_KEY *(*open_key_abs) (REG_HANDLE *, const char *name);
REG_KEY_LIST *(*get_subkeys) (REG_KEY *);
REG_VAL_LIST *(*get_values) (REG_KEY *);
BOOL (*add_key)(REG_KEY *, REG_KEY *);
BOOL (*update_key)(REG_KEY *);
BOOL (*del_key)(REG_KEY *);
BOOL (*add_value)(REG_KEY *, REG_VAL *);
BOOL (*update_value)(REG_VAL *);
BOOL (*del_value)(REG_VAL *);
REG_VAL *(*get_value) (REG_KEY *, const char *name);
/* It is not guaranteed that no data has been stored before save()
* has been called. This function is only useful for backends that
* store the data in memory and then write out the whole registry at once */
BOOL (*save)(REG_HANDLE *, const char *location);
BOOL (*close_registry) (REG_HANDLE *);
void (*free_key)(REG_KEY *);
void (*free_value)(REG_VAL *);
} REGISTRY_OPS;
</programlisting>
<para>open_root_key() is optional. It's only called if the
<parameter>root</parameter> field of the REG_HANDLE struct is NULL.</para>
<para>open_key_abs() is optional. If it's NULL, the frontend will
provide a replacement, using open_key_rel().</para>
<para>get_values() and get_value() are optional. They're only called if
the <parameter>values</parameter> field of the REG_KEY struct is NULL.</para>
<para>get_subkeys() and get_key() are optional. THey're only called
if the <parameter>subkeys</parameter> field of the REG_KEY struct is NULL.</para>
</sect1>
<sect1><title>Memory allocation</title>
<para>Okay, so who's responsible for what parts of the memory? </para>
<para>The memory is basically maintained by the backends. When the user
is finished using a particular structure, it should call the related free
function for the structure it's freeing.</para>
<para>The backend should then decide what to do with the structure. It may
choose to free it, or, if it's maintaining single copies of everything in
memory, may choose to ignore the free and free it when the registry is closed.
</para>
</sect1>
</chapter>
|