registry: Implement recursive deletes for dir-backed registry.
[samba.git] / source4 / lib / registry / dir.c
1 /*
2    Unix SMB/CIFS implementation.
3    Registry interface
4    Copyright (C) Jelmer Vernooij                                  2004-2007.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "hive.h"
22 #include "system/dir.h"
23 #include "system/filesys.h"
24
25 struct dir_key {
26         struct hive_key key;
27         const char *path;
28 };
29
30 static struct hive_operations reg_backend_dir;
31
32 static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx,
33                               const struct hive_key *parent,
34                               const char *name, const char *classname,
35                               struct security_descriptor *desc,
36                               struct hive_key **result)
37 {
38         struct dir_key *dk = talloc_get_type(parent, struct dir_key);
39         char *path;
40         int ret;
41
42         path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
43         ret = mkdir(path, 0700);
44         if (ret == 0) {
45                 struct dir_key *key = talloc(mem_ctx, struct dir_key);
46                 key->key.ops = &reg_backend_dir;
47                 key->path = talloc_steal(key, path);
48                 *result = (struct hive_key *)key;
49                 return WERR_OK;
50         }
51
52         if (errno == EEXIST)
53                 return WERR_ALREADY_EXISTS;
54         printf("FAILED %s BECAUSE: %s\n", path, strerror(errno));
55         return WERR_GENERAL_FAILURE;
56 }
57
58 static WERROR reg_dir_delete_recursive(const char *name)
59 {
60         DIR *d;
61         struct dirent *e;
62         WERROR werr;
63
64         d = opendir(name);
65         if (d == NULL) {
66                 DEBUG(3,("Unable to open '%s': %s\n", name,
67                       strerror(errno)));
68                 return WERR_BADFILE;
69         }
70
71         while((e = readdir(d))) {
72                 char *path;
73                 struct stat stbuf;
74
75                 if (ISDOT(e->d_name) || ISDOTDOT(e->d_name))
76                         continue;
77
78                 path = talloc_asprintf(name, "%s/%s", name, e->d_name);
79                 if (!path)
80                         return WERR_NOMEM;
81
82                 stat(path, &stbuf);
83
84                 if (!S_ISDIR(stbuf.st_mode)) {
85                         if (unlink(path) < 0) {
86                                 talloc_free(path);
87                                 closedir(d);
88                                 return WERR_GENERAL_FAILURE;
89                         }
90                 } else {
91                         werr = reg_dir_delete_recursive(path);
92                         if (!W_ERROR_IS_OK(werr)) {
93                                 talloc_free(path);
94                                 closedir(d);
95                                 return werr;
96                         }
97                 }
98
99                 talloc_free(path);
100         }
101         closedir(d);
102
103         if (rmdir(name) == 0)
104                 return WERR_OK;
105         else if (errno == ENOENT)
106                 return WERR_BADFILE;
107         else
108                 return WERR_GENERAL_FAILURE;
109 }
110
111 static WERROR reg_dir_del_key(const struct hive_key *k, const char *name)
112 {
113         struct dir_key *dk = talloc_get_type(k, struct dir_key);
114         char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name);
115         WERROR ret;
116
117         ret = reg_dir_delete_recursive(child);
118
119         talloc_free(child);
120
121         return ret;
122 }
123
124 static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx,
125                                const struct hive_key *parent,
126                                const char *name, struct hive_key **subkey)
127 {
128         DIR *d;
129         char *fullpath;
130         const struct dir_key *p = talloc_get_type(parent, struct dir_key);
131         struct dir_key *ret;
132
133         if (name == NULL) {
134                 DEBUG(0, ("NULL pointer passed as directory name!"));
135                 return WERR_INVALID_PARAM;
136         }
137
138         fullpath = talloc_asprintf(mem_ctx, "%s/%s", p->path, name);
139
140         d = opendir(fullpath);
141         if (d == NULL) {
142                 DEBUG(3,("Unable to open '%s': %s\n", fullpath,
143                         strerror(errno)));
144                 return WERR_BADFILE;
145         }
146         closedir(d);
147         ret = talloc(mem_ctx, struct dir_key);
148         ret->key.ops = &reg_backend_dir;
149         ret->path = talloc_steal(ret, fullpath);
150         *subkey = (struct hive_key *)ret;
151         return WERR_OK;
152 }
153
154 static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx,
155                                    const struct hive_key *k, uint32_t idx,
156                                    const char **name,
157                                    const char **classname,
158                                    NTTIME *last_mod_time)
159 {
160         struct dirent *e;
161         const struct dir_key *dk = talloc_get_type(k, struct dir_key);
162         int i = 0;
163         DIR *d;
164
165         d = opendir(dk->path);
166
167         if (d == NULL)
168                 return WERR_INVALID_PARAM;
169
170         while((e = readdir(d))) {
171                 if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
172                         struct stat stbuf;
173                         char *thispath;
174
175                         /* Check if file is a directory */
176                         asprintf(&thispath, "%s/%s", dk->path, e->d_name);
177                         stat(thispath, &stbuf);
178
179                         if (!S_ISDIR(stbuf.st_mode)) {
180                                 SAFE_FREE(thispath);
181                                 continue;
182                         }
183
184                         if (i == idx) {
185                                 struct stat st;
186                                 *name = talloc_strdup(mem_ctx, e->d_name);
187                                 *classname = NULL;
188                                 stat(thispath, &st);
189                                 unix_to_nt_time(last_mod_time, st.st_mtime);
190                                 SAFE_FREE(thispath);
191                                 closedir(d);
192                                 return WERR_OK;
193                         }
194                         i++;
195
196                         SAFE_FREE(thispath);
197                 }
198         }
199
200         closedir(d);
201
202         return WERR_NO_MORE_ITEMS;
203 }
204
205 WERROR reg_open_directory(TALLOC_CTX *parent_ctx,
206                           const char *location, struct hive_key **key)
207 {
208         struct dir_key *dk;
209
210         if (location == NULL)
211                 return WERR_INVALID_PARAM;
212
213         dk = talloc(parent_ctx, struct dir_key);
214         dk->key.ops = &reg_backend_dir;
215         dk->path = talloc_strdup(dk, location);
216         *key = (struct hive_key *)dk;
217         return WERR_OK;
218 }
219
220 WERROR reg_create_directory(TALLOC_CTX *parent_ctx,
221                             const char *location, struct hive_key **key)
222 {
223         if (mkdir(location, 0700) != 0) {
224                 *key = NULL;
225                 return WERR_GENERAL_FAILURE;
226         }
227
228         return reg_open_directory(parent_ctx, location, key);
229 }
230
231 static WERROR reg_dir_get_info(TALLOC_CTX *ctx, const struct hive_key *key,
232                                const char **classname,
233                                uint32_t *num_subkeys,
234                                uint32_t *num_values,
235                                NTTIME *lastmod,
236                                uint32_t *max_subkeynamelen,
237                                uint32_t *max_valnamelen,
238                                uint32_t *max_valbufsize)
239 {
240         DIR *d;
241         const struct dir_key *dk = talloc_get_type(key, struct dir_key);
242         struct dirent *e;
243         struct stat st;
244
245         SMB_ASSERT(key != NULL);
246
247         if (classname != NULL)
248                 *classname = NULL;
249
250         d = opendir(dk->path);
251         if (d == NULL)
252                 return WERR_INVALID_PARAM;
253
254         if (num_subkeys != NULL)
255                 *num_subkeys = 0;
256
257         if (num_values != NULL)
258                 *num_values = 0;
259
260         if (max_subkeynamelen != NULL)
261                 *max_subkeynamelen = 0;
262
263         if (max_valnamelen != NULL)
264                 *max_valnamelen = 0;
265
266         if (max_valbufsize != NULL)
267                 *max_valbufsize = 0;
268
269         while((e = readdir(d))) {
270                 if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
271                         char *path = talloc_asprintf(ctx, "%s/%s",
272                                                      dk->path, e->d_name);
273
274                         if (stat(path, &st) < 0) {
275                                 DEBUG(0, ("Error statting %s: %s\n", path,
276                                         strerror(errno)));
277                                 continue;
278                         }
279
280                         if (S_ISDIR(st.st_mode)) {
281                                 if (num_subkeys != NULL)
282                                         (*num_subkeys)++;
283                                 if (max_subkeynamelen != NULL)
284                                         *max_subkeynamelen = MAX(*max_subkeynamelen, strlen(e->d_name));
285                         }
286
287                         if (!S_ISDIR(st.st_mode)) {
288                                 if (num_values != NULL)
289                                         (*num_values)++;
290                                 if (max_valnamelen != NULL)
291                                         *max_valnamelen = MAX(*max_valnamelen, strlen(e->d_name));
292                                 if (max_valbufsize != NULL)
293                                         *max_valbufsize = MAX(*max_valbufsize, st.st_size);
294                         }
295
296                         talloc_free(path);
297                 }
298         }
299
300         closedir(d);
301
302         if (lastmod != NULL)
303                 *lastmod = 0;
304         return WERR_OK;
305 }
306
307 static WERROR reg_dir_set_value(struct hive_key *key, const char *name,
308                                 uint32_t type, const DATA_BLOB data)
309 {
310         const struct dir_key *dk = talloc_get_type(key, struct dir_key);
311         char *path = talloc_asprintf(dk, "%s/%s", dk->path, name);
312
313         if (!file_save(path, data.data, data.length))
314                 return WERR_GENERAL_FAILURE;
315
316         /* FIXME: Type */
317
318         return WERR_OK;
319 }
320
321 static WERROR reg_dir_get_value(TALLOC_CTX *mem_ctx,
322                                 struct hive_key *key, const char *name,
323                                 uint32_t *type, DATA_BLOB *data)
324 {
325         const struct dir_key *dk = talloc_get_type(key, struct dir_key);
326         char *path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
327         size_t size;
328         char *contents;
329
330         contents = file_load(path, &size, mem_ctx);
331         talloc_free(path);
332         if (contents == NULL)
333                 return WERR_BADFILE;
334
335         if (type != NULL)
336                 *type = 4; /* FIXME */
337
338         data->data = (uint8_t *)contents;
339         data->length = size;
340
341         return WERR_OK;
342 }
343
344 static WERROR reg_dir_enum_value(TALLOC_CTX *mem_ctx,
345                                  struct hive_key *key, int idx,
346                                  const char **name,
347                                  uint32_t *type, DATA_BLOB *data)
348 {
349         const struct dir_key *dk = talloc_get_type(key, struct dir_key);
350         DIR *d;
351         struct dirent *e;
352         int i;
353
354         d = opendir(dk->path);
355         if (d == NULL) {
356                 DEBUG(3,("Unable to open '%s': %s\n", dk->path,
357                         strerror(errno)));
358                 return WERR_BADFILE;
359         }
360
361         i = 0;
362         while((e = readdir(d))) {
363                 if (ISDOT(e->d_name) || ISDOTDOT(e->d_name))
364                         continue;
365
366                 if (i == idx) {
367                         if (name != NULL)
368                                 *name = talloc_strdup(mem_ctx, e->d_name);
369                         W_ERROR_NOT_OK_RETURN(reg_dir_get_value(mem_ctx, key,
370                                                                 *name, type,
371                                                                 data));
372                         return WERR_OK;
373                 }
374
375                 i++;
376         }
377         closedir(d);
378
379         return WERR_NO_MORE_ITEMS;
380 }
381
382
383 static WERROR reg_dir_del_value (struct hive_key *key, const char *name)
384 {
385         const struct dir_key *dk = talloc_get_type(key, struct dir_key);
386         char *path = talloc_asprintf(key, "%s/%s", dk->path, name);
387         if (unlink(path) < 0) {
388                 talloc_free(path);
389                 if (errno == ENOENT)
390                         return WERR_BADFILE;
391                 return WERR_GENERAL_FAILURE;
392         }
393         talloc_free(path);
394
395         return WERR_OK;
396 }
397
398 static struct hive_operations reg_backend_dir = {
399         .name = "dir",
400         .get_key_by_name = reg_dir_open_key,
401         .get_key_info = reg_dir_get_info,
402         .add_key = reg_dir_add_key,
403         .del_key = reg_dir_del_key,
404         .enum_key = reg_dir_key_by_index,
405         .set_value = reg_dir_set_value,
406         .get_value_by_name = reg_dir_get_value,
407         .enum_value = reg_dir_enum_value,
408         .delete_value = reg_dir_del_value,
409 };