util_tdb: make the _byblob fetch/store functions public again.
[samba.git] / source3 / lib / util_tdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    tdb utility functions
4    Copyright (C) Andrew Tridgell   1992-1998
5    Copyright (C) Rafal Szczesniak  2002
6    Copyright (C) Michael Adam      2007
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #undef malloc
24 #undef realloc
25 #undef calloc
26 #undef strdup
27
28 /* these are little tdb utility functions that are meant to make
29    dealing with a tdb database a little less cumbersome in Samba */
30
31 static SIG_ATOMIC_T gotalarm;
32
33 /***************************************************************
34  Signal function to tell us we timed out.
35 ****************************************************************/
36
37 static void gotalarm_sig(void)
38 {
39         gotalarm = 1;
40 }
41
42 /***************************************************************
43  Make a TDB_DATA and keep the const warning in one place
44 ****************************************************************/
45
46 TDB_DATA make_tdb_data(const uint8 *dptr, size_t dsize)
47 {
48         TDB_DATA ret;
49         ret.dptr = CONST_DISCARD(uint8 *, dptr);
50         ret.dsize = dsize;
51         return ret;
52 }
53
54 TDB_DATA string_tdb_data(const char *string)
55 {
56         return make_tdb_data((const uint8 *)string, string ? strlen(string) : 0 );
57 }
58
59 TDB_DATA string_term_tdb_data(const char *string)
60 {
61         return make_tdb_data((const uint8 *)string, string ? strlen(string) + 1 : 0);
62 }
63
64 /****************************************************************************
65  Lock a chain with timeout (in seconds).
66 ****************************************************************************/
67
68 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
69 {
70         /* Allow tdb_chainlock to be interrupted by an alarm. */
71         int ret;
72         gotalarm = 0;
73
74         if (timeout) {
75                 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
76                 tdb_setalarm_sigptr(tdb, &gotalarm);
77                 alarm(timeout);
78         }
79
80         if (rw_type == F_RDLCK)
81                 ret = tdb_chainlock_read(tdb, key);
82         else
83                 ret = tdb_chainlock(tdb, key);
84
85         if (timeout) {
86                 alarm(0);
87                 tdb_setalarm_sigptr(tdb, NULL);
88                 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
89                 if (gotalarm) {
90                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
91                                 timeout, key.dptr, tdb_name(tdb)));
92                         /* TODO: If we time out waiting for a lock, it might
93                          * be nice to use F_GETLK to get the pid of the
94                          * process currently holding the lock and print that
95                          * as part of the debugging message. -- mbp */
96                         return -1;
97                 }
98         }
99
100         return ret;
101 }
102
103 /****************************************************************************
104  Write lock a chain. Return -1 if timeout or lock failed.
105 ****************************************************************************/
106
107 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
108 {
109         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
110 }
111
112 /****************************************************************************
113  Lock a chain by string. Return -1 if timeout or lock failed.
114 ****************************************************************************/
115
116 int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval)
117 {
118         TDB_DATA key = string_term_tdb_data(keyval);
119         
120         return tdb_chainlock(tdb, key);
121 }
122
123 int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
124                                    int timeout)
125 {
126         TDB_DATA key = string_term_tdb_data(keyval);
127         
128         return tdb_chainlock_with_timeout(tdb, key, timeout);
129 }
130
131 /****************************************************************************
132  Unlock a chain by string.
133 ****************************************************************************/
134
135 void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
136 {
137         TDB_DATA key = string_term_tdb_data(keyval);
138
139         tdb_chainunlock(tdb, key);
140 }
141
142 /****************************************************************************
143  Read lock a chain by string. Return -1 if timeout or lock failed.
144 ****************************************************************************/
145
146 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
147 {
148         TDB_DATA key = string_term_tdb_data(keyval);
149         
150         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
151 }
152
153 /****************************************************************************
154  Read unlock a chain by string.
155 ****************************************************************************/
156
157 void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
158 {
159         TDB_DATA key = string_term_tdb_data(keyval);
160         
161         tdb_chainunlock_read(tdb, key);
162 }
163
164
165 /****************************************************************************
166  Fetch a int32 value by a arbitrary blob key, return -1 if not found.
167  Output is int32 in native byte order.
168 ****************************************************************************/
169
170 int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key)
171 {
172         TDB_DATA data;
173         int32 ret;
174
175         data = tdb_fetch(tdb, key);
176         if (!data.dptr || data.dsize != sizeof(int32)) {
177                 SAFE_FREE(data.dptr);
178                 return -1;
179         }
180
181         ret = IVAL(data.dptr,0);
182         SAFE_FREE(data.dptr);
183         return ret;
184 }
185
186 /****************************************************************************
187  Fetch a int32 value by string key, return -1 if not found.
188  Output is int32 in native byte order.
189 ****************************************************************************/
190
191 int32 tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
192 {
193         TDB_DATA key = string_term_tdb_data(keystr);
194
195         return tdb_fetch_int32_byblob(tdb, key);
196 }
197
198 /****************************************************************************
199  Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
200  Input is int32 in native byte order. Output in tdb is in little-endian.
201 ****************************************************************************/
202
203 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, int32 v)
204 {
205         TDB_DATA data;
206         int32 v_store;
207
208         SIVAL(&v_store,0,v);
209         data.dptr = (uint8 *)&v_store;
210         data.dsize = sizeof(int32);
211
212         return tdb_store(tdb, key, data, TDB_REPLACE);
213 }
214
215 /****************************************************************************
216  Store a int32 value by string key, return 0 on success, -1 on failure.
217  Input is int32 in native byte order. Output in tdb is in little-endian.
218 ****************************************************************************/
219
220 int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32 v)
221 {
222         TDB_DATA key = string_term_tdb_data(keystr);
223
224         return tdb_store_int32_byblob(tdb, key, v);
225 }
226
227 /****************************************************************************
228  Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
229  Output is uint32 in native byte order.
230 ****************************************************************************/
231
232 bool tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 *value)
233 {
234         TDB_DATA data;
235
236         data = tdb_fetch(tdb, key);
237         if (!data.dptr || data.dsize != sizeof(uint32)) {
238                 SAFE_FREE(data.dptr);
239                 return False;
240         }
241
242         *value = IVAL(data.dptr,0);
243         SAFE_FREE(data.dptr);
244         return True;
245 }
246
247 /****************************************************************************
248  Fetch a uint32 value by string key, return -1 if not found.
249  Output is uint32 in native byte order.
250 ****************************************************************************/
251
252 bool tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 *value)
253 {
254         TDB_DATA key = string_term_tdb_data(keystr);
255
256         return tdb_fetch_uint32_byblob(tdb, key, value);
257 }
258
259 /****************************************************************************
260  Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
261  Input is uint32 in native byte order. Output in tdb is in little-endian.
262 ****************************************************************************/
263
264 bool tdb_store_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 value)
265 {
266         TDB_DATA data;
267         uint32 v_store;
268         bool ret = True;
269
270         SIVAL(&v_store, 0, value);
271         data.dptr = (uint8 *)&v_store;
272         data.dsize = sizeof(uint32);
273
274         if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
275                 ret = False;
276
277         return ret;
278 }
279
280 /****************************************************************************
281  Store a uint32 value by string key, return 0 on success, -1 on failure.
282  Input is uint32 in native byte order. Output in tdb is in little-endian.
283 ****************************************************************************/
284
285 bool tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 value)
286 {
287         TDB_DATA key = string_term_tdb_data(keystr);
288
289         return tdb_store_uint32_byblob(tdb, key, value);
290 }
291 /****************************************************************************
292  Store a buffer by a null terminated string key.  Return 0 on success, -1
293  on failure.
294 ****************************************************************************/
295
296 int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
297 {
298         TDB_DATA key = string_term_tdb_data(keystr);
299
300         return tdb_store(tdb, key, data, flags);
301 }
302
303 int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
304                              TDB_DATA data, int flags)
305 {
306         TDB_DATA key = string_term_tdb_data(keystr);
307         
308         return tdb_trans_store(tdb, key, data, flags);
309 }
310
311 /****************************************************************************
312  Fetch a buffer using a null terminated string key.  Don't forget to call
313  free() on the result dptr.
314 ****************************************************************************/
315
316 TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
317 {
318         TDB_DATA key = string_term_tdb_data(keystr);
319
320         return tdb_fetch(tdb, key);
321 }
322
323 /****************************************************************************
324  Delete an entry using a null terminated string key. 
325 ****************************************************************************/
326
327 int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
328 {
329         TDB_DATA key = string_term_tdb_data(keystr);
330
331         return tdb_delete(tdb, key);
332 }
333
334 /****************************************************************************
335  Atomic integer change. Returns old value. To create, set initial value in *oldval. 
336 ****************************************************************************/
337
338 int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32 *oldval, int32 change_val)
339 {
340         int32 val;
341         int32 ret = -1;
342
343         if (tdb_lock_bystring(tdb, keystr) == -1)
344                 return -1;
345
346         if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
347                 /* The lookup failed */
348                 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
349                         /* but not because it didn't exist */
350                         goto err_out;
351                 }
352                 
353                 /* Start with 'old' value */
354                 val = *oldval;
355
356         } else {
357                 /* It worked, set return value (oldval) to tdb data */
358                 *oldval = val;
359         }
360
361         /* Increment value for storage and return next time */
362         val += change_val;
363                 
364         if (tdb_store_int32(tdb, keystr, val) == -1)
365                 goto err_out;
366
367         ret = 0;
368
369   err_out:
370
371         tdb_unlock_bystring(tdb, keystr);
372         return ret;
373 }
374
375 /****************************************************************************
376  Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval. 
377 ****************************************************************************/
378
379 bool tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32 *oldval, uint32 change_val)
380 {
381         uint32 val;
382         bool ret = False;
383
384         if (tdb_lock_bystring(tdb, keystr) == -1)
385                 return False;
386
387         if (!tdb_fetch_uint32(tdb, keystr, &val)) {
388                 /* It failed */
389                 if (tdb_error(tdb) != TDB_ERR_NOEXIST) { 
390                         /* and not because it didn't exist */
391                         goto err_out;
392                 }
393
394                 /* Start with 'old' value */
395                 val = *oldval;
396
397         } else {
398                 /* it worked, set return value (oldval) to tdb data */
399                 *oldval = val;
400
401         }
402
403         /* get a new value to store */
404         val += change_val;
405                 
406         if (!tdb_store_uint32(tdb, keystr, val))
407                 goto err_out;
408
409         ret = True;
410
411   err_out:
412
413         tdb_unlock_bystring(tdb, keystr);
414         return ret;
415 }
416
417 /****************************************************************************
418  Useful pair of routines for packing/unpacking data consisting of
419  integers and strings.
420 ****************************************************************************/
421
422 static size_t tdb_pack_va(uint8 *buf, int bufsize, const char *fmt, va_list ap)
423 {
424         uint8 bt;
425         uint16 w;
426         uint32 d;
427         int i;
428         void *p;
429         int len;
430         char *s;
431         char c;
432         uint8 *buf0 = buf;
433         const char *fmt0 = fmt;
434         int bufsize0 = bufsize;
435
436         while (*fmt) {
437                 switch ((c = *fmt++)) {
438                 case 'b': /* unsigned 8-bit integer */
439                         len = 1;
440                         bt = (uint8)va_arg(ap, int);
441                         if (bufsize && bufsize >= len)
442                                 SSVAL(buf, 0, bt);
443                         break;
444                 case 'w': /* unsigned 16-bit integer */
445                         len = 2;
446                         w = (uint16)va_arg(ap, int);
447                         if (bufsize && bufsize >= len)
448                                 SSVAL(buf, 0, w);
449                         break;
450                 case 'd': /* signed 32-bit integer (standard int in most systems) */
451                         len = 4;
452                         d = va_arg(ap, uint32);
453                         if (bufsize && bufsize >= len)
454                                 SIVAL(buf, 0, d);
455                         break;
456                 case 'p': /* pointer */
457                         len = 4;
458                         p = va_arg(ap, void *);
459                         d = p?1:0;
460                         if (bufsize && bufsize >= len)
461                                 SIVAL(buf, 0, d);
462                         break;
463                 case 'P': /* null-terminated string */
464                         s = va_arg(ap,char *);
465                         w = strlen(s);
466                         len = w + 1;
467                         if (bufsize && bufsize >= len)
468                                 memcpy(buf, s, len);
469                         break;
470                 case 'f': /* null-terminated string */
471                         s = va_arg(ap,char *);
472                         w = strlen(s);
473                         len = w + 1;
474                         if (bufsize && bufsize >= len)
475                                 memcpy(buf, s, len);
476                         break;
477                 case 'B': /* fixed-length string */
478                         i = va_arg(ap, int);
479                         s = va_arg(ap, char *);
480                         len = 4+i;
481                         if (bufsize && bufsize >= len) {
482                                 SIVAL(buf, 0, i);
483                                 memcpy(buf+4, s, i);
484                         }
485                         break;
486                 default:
487                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
488                                  c, fmt));
489                         len = 0;
490                         break;
491                 }
492
493                 buf += len;
494                 if (bufsize)
495                         bufsize -= len;
496                 if (bufsize < 0)
497                         bufsize = 0;
498         }
499
500         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
501                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
502         
503         return PTR_DIFF(buf, buf0);
504 }
505
506 size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...)
507 {
508         va_list ap;
509         size_t result;
510
511         va_start(ap, fmt);
512         result = tdb_pack_va(buf, bufsize, fmt, ap);
513         va_end(ap);
514         return result;
515 }
516
517 bool tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
518                      const char *fmt, ...)
519 {
520         va_list ap;
521         size_t len1, len2;
522
523         va_start(ap, fmt);
524         len1 = tdb_pack_va(NULL, 0, fmt, ap);
525         va_end(ap);
526
527         if (mem_ctx != NULL) {
528                 *buf = TALLOC_REALLOC_ARRAY(mem_ctx, *buf, uint8,
529                                             (*len) + len1);
530         } else {
531                 *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
532         }
533
534         if (*buf == NULL) {
535                 return False;
536         }
537
538         va_start(ap, fmt);
539         len2 = tdb_pack_va((*buf)+(*len), len1, fmt, ap);
540         va_end(ap);
541
542         if (len1 != len2) {
543                 return False;
544         }
545
546         *len += len2;
547
548         return True;
549 }
550
551 /****************************************************************************
552  Useful pair of routines for packing/unpacking data consisting of
553  integers and strings.
554 ****************************************************************************/
555
556 int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...)
557 {
558         va_list ap;
559         uint8 *bt;
560         uint16 *w;
561         uint32 *d;
562         int len;
563         int *i;
564         void **p;
565         char *s, **b, **ps;
566         char c;
567         const uint8 *buf0 = buf;
568         const char *fmt0 = fmt;
569         int bufsize0 = bufsize;
570
571         va_start(ap, fmt);
572
573         while (*fmt) {
574                 switch ((c=*fmt++)) {
575                 case 'b':
576                         len = 1;
577                         bt = va_arg(ap, uint8 *);
578                         if (bufsize < len)
579                                 goto no_space;
580                         *bt = SVAL(buf, 0);
581                         break;
582                 case 'w':
583                         len = 2;
584                         w = va_arg(ap, uint16 *);
585                         if (bufsize < len)
586                                 goto no_space;
587                         *w = SVAL(buf, 0);
588                         break;
589                 case 'd':
590                         len = 4;
591                         d = va_arg(ap, uint32 *);
592                         if (bufsize < len)
593                                 goto no_space;
594                         *d = IVAL(buf, 0);
595                         break;
596                 case 'p':
597                         len = 4;
598                         p = va_arg(ap, void **);
599                         if (bufsize < len)
600                                 goto no_space;
601                         /*
602                          * This isn't a real pointer - only a token (1 or 0)
603                          * to mark the fact a pointer is present.
604                          */
605
606                         *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
607                         break;
608                 case 'P':
609                         /* Return malloc'ed string. */
610                         ps = va_arg(ap,char **);
611                         len = strlen((const char *)buf) + 1;
612                         *ps = SMB_STRDUP((const char *)buf);
613                         break;
614                 case 'f':
615                         s = va_arg(ap,char *);
616                         len = strlen((const char *)buf) + 1;
617                         if (bufsize < len || len > sizeof(fstring))
618                                 goto no_space;
619                         memcpy(s, buf, len);
620                         break;
621                 case 'B':
622                         i = va_arg(ap, int *);
623                         b = va_arg(ap, char **);
624                         len = 4;
625                         if (bufsize < len)
626                                 goto no_space;
627                         *i = IVAL(buf, 0);
628                         if (! *i) {
629                                 *b = NULL;
630                                 break;
631                         }
632                         len += *i;
633                         if (bufsize < len)
634                                 goto no_space;
635                         *b = (char *)SMB_MALLOC(*i);
636                         if (! *b)
637                                 goto no_space;
638                         memcpy(*b, buf+4, *i);
639                         break;
640                 default:
641                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
642                                  c, fmt));
643
644                         len = 0;
645                         break;
646                 }
647
648                 buf += len;
649                 bufsize -= len;
650         }
651
652         va_end(ap);
653
654         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
655                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
656
657         return PTR_DIFF(buf, buf0);
658
659  no_space:
660         va_end(ap);
661         return -1;
662 }
663
664
665 /****************************************************************************
666  Log tdb messages via DEBUG().
667 ****************************************************************************/
668
669 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
670 {
671         va_list ap;
672         char *ptr = NULL;
673         int ret;
674
675         va_start(ap, format);
676         ret = vasprintf(&ptr, format, ap);
677         va_end(ap);
678
679         if ((ret == -1) || !*ptr)
680                 return;
681
682         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
683         SAFE_FREE(ptr);
684 }
685
686 /****************************************************************************
687  Like tdb_open() but also setup a logging function that redirects to
688  the samba DEBUG() system.
689 ****************************************************************************/
690
691 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
692                           int open_flags, mode_t mode)
693 {
694         TDB_CONTEXT *tdb;
695         struct tdb_logging_context log_ctx;
696
697         if (!lp_use_mmap())
698                 tdb_flags |= TDB_NOMMAP;
699
700         log_ctx.log_fn = tdb_log;
701         log_ctx.log_private = NULL;
702
703         if ((hash_size == 0) && (name != NULL)) {
704                 const char *base = strrchr_m(name, '/');
705                 if (base != NULL) {
706                         base += 1;
707                 }
708                 else {
709                         base = name;
710                 }
711                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
712         }
713
714         tdb = tdb_open_ex(name, hash_size, tdb_flags, 
715                           open_flags, mode, &log_ctx, NULL);
716         if (!tdb)
717                 return NULL;
718
719         return tdb;
720 }
721
722 /****************************************************************************
723  Allow tdb_delete to be used as a tdb_traversal_fn.
724 ****************************************************************************/
725
726 static int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key,
727                                   TDB_DATA dbuf, void *state)
728 {
729     return tdb_delete(the_tdb, key);
730 }
731
732 int tdb_wipe(TDB_CONTEXT *tdb)
733 {
734         return tdb_traverse(tdb, tdb_traverse_delete_fn, NULL);
735 }
736
737
738
739
740 /**
741  * Search across the whole tdb for keys that match the given pattern
742  * return the result as a list of keys
743  *
744  * @param tdb pointer to opened tdb file context
745  * @param pattern searching pattern used by fnmatch(3) functions
746  *
747  * @return list of keys found by looking up with given pattern
748  **/
749 TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
750 {
751         TDB_DATA key, next;
752         TDB_LIST_NODE *list = NULL;
753         TDB_LIST_NODE *rec = NULL;
754         
755         for (key = tdb_firstkey(tdb); key.dptr; key = next) {
756                 /* duplicate key string to ensure null-termination */
757                 char *key_str = SMB_STRNDUP((const char *)key.dptr, key.dsize);
758                 if (!key_str) {
759                         DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
760                         smb_panic("strndup failed!\n");
761                 }
762                 
763                 DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
764                 
765                 next = tdb_nextkey(tdb, key);
766
767                 /* do the pattern checking */
768                 if (fnmatch(pattern, key_str, 0) == 0) {
769                         rec = SMB_MALLOC_P(TDB_LIST_NODE);
770                         ZERO_STRUCTP(rec);
771
772                         rec->node_key = key;
773         
774                         DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
775                 
776                         DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
777                 } else {
778                         free(key.dptr);
779                 }
780                 
781                 /* free duplicated key string */
782                 free(key_str);
783         }
784         
785         return list;
786
787 }
788
789
790 /**
791  * Free the list returned by tdb_search_keys
792  *
793  * @param node list of results found by tdb_search_keys
794  **/
795 void tdb_search_list_free(TDB_LIST_NODE* node)
796 {
797         TDB_LIST_NODE *next_node;
798         
799         while (node) {
800                 next_node = node->next;
801                 SAFE_FREE(node->node_key.dptr);
802                 SAFE_FREE(node);
803                 node = next_node;
804         };
805 }
806
807 /****************************************************************************
808  tdb_store, wrapped in a transaction. This way we make sure that a process
809  that dies within writing does not leave a corrupt tdb behind.
810 ****************************************************************************/
811
812 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
813                     int flag)
814 {
815         int res;
816
817         if ((res = tdb_transaction_start(tdb)) != 0) {
818                 DEBUG(5, ("tdb_transaction_start failed\n"));
819                 return res;
820         }
821
822         if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
823                 DEBUG(10, ("tdb_store failed\n"));
824                 if (tdb_transaction_cancel(tdb) != 0) {
825                         smb_panic("Cancelling transaction failed");
826                 }
827                 return res;
828         }
829
830         if ((res = tdb_transaction_commit(tdb)) != 0) {
831                 DEBUG(5, ("tdb_transaction_commit failed\n"));
832         }
833
834         return res;
835 }
836
837 /****************************************************************************
838  tdb_delete, wrapped in a transaction. This way we make sure that a process
839  that dies within deleting does not leave a corrupt tdb behind.
840 ****************************************************************************/
841
842 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
843 {
844         int res;
845
846         if ((res = tdb_transaction_start(tdb)) != 0) {
847                 DEBUG(5, ("tdb_transaction_start failed\n"));
848                 return res;
849         }
850
851         if ((res = tdb_delete(tdb, key)) != 0) {
852                 DEBUG(10, ("tdb_delete failed\n"));
853                 if (tdb_transaction_cancel(tdb) != 0) {
854                         smb_panic("Cancelling transaction failed");
855                 }
856                 return res;
857         }
858
859         if ((res = tdb_transaction_commit(tdb)) != 0) {
860                 DEBUG(5, ("tdb_transaction_commit failed\n"));
861         }
862
863         return res;
864 }
865
866 /*
867  Log tdb messages via DEBUG().
868 */
869 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
870                          const char *format, ...) PRINTF_ATTRIBUTE(3,4);
871
872 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
873                          const char *format, ...)
874 {
875         va_list ap;
876         char *ptr = NULL;
877         int debuglevel = 0;
878         int ret;
879
880         switch (level) {
881         case TDB_DEBUG_FATAL:
882                 debug_level = 0;
883                 break;
884         case TDB_DEBUG_ERROR:
885                 debuglevel = 1;
886                 break;
887         case TDB_DEBUG_WARNING:
888                 debuglevel = 2;
889                 break;
890         case TDB_DEBUG_TRACE:
891                 debuglevel = 5;
892                 break;
893         default:
894                 debuglevel = 0;
895         }               
896
897         va_start(ap, format);
898         ret = vasprintf(&ptr, format, ap);
899         va_end(ap);
900
901         if (ret != -1) {
902                 const char *name = tdb_name(tdb);
903                 DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
904                 free(ptr);
905         }
906 }
907
908 static struct tdb_wrap *tdb_list;
909
910 /* destroy the last connection to a tdb */
911 static int tdb_wrap_destructor(struct tdb_wrap *w)
912 {
913         tdb_close(w->tdb);
914         DLIST_REMOVE(tdb_list, w);
915         return 0;
916 }                                
917
918 /*
919   wrapped connection to a tdb database
920   to close just talloc_free() the tdb_wrap pointer
921  */
922 struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
923                                const char *name, int hash_size, int tdb_flags,
924                                int open_flags, mode_t mode)
925 {
926         struct tdb_wrap *w;
927         struct tdb_logging_context log_ctx;
928         log_ctx.log_fn = tdb_wrap_log;
929
930         if (!lp_use_mmap())
931                 tdb_flags |= TDB_NOMMAP;
932
933         for (w=tdb_list;w;w=w->next) {
934                 if (strcmp(name, w->name) == 0) {
935                         /*
936                          * Yes, talloc_reference is exactly what we want
937                          * here. Otherwise we would have to implement our own
938                          * reference counting.
939                          */
940                         return talloc_reference(mem_ctx, w);
941                 }
942         }
943
944         w = talloc(mem_ctx, struct tdb_wrap);
945         if (w == NULL) {
946                 return NULL;
947         }
948
949         if (!(w->name = talloc_strdup(w, name))) {
950                 talloc_free(w);
951                 return NULL;
952         }
953
954         if ((hash_size == 0) && (name != NULL)) {
955                 const char *base = strrchr_m(name, '/');
956                 if (base != NULL) {
957                         base += 1;
958                 }
959                 else {
960                         base = name;
961                 }
962                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
963         }
964
965         w->tdb = tdb_open_ex(name, hash_size, tdb_flags, 
966                              open_flags, mode, &log_ctx, NULL);
967         if (w->tdb == NULL) {
968                 talloc_free(w);
969                 return NULL;
970         }
971
972         talloc_set_destructor(w, tdb_wrap_destructor);
973
974         DLIST_ADD(tdb_list, w);
975
976         return w;
977 }
978
979 NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
980 {
981         struct { enum TDB_ERROR err; NTSTATUS status; } map[] =
982                 { { TDB_SUCCESS,        NT_STATUS_OK },
983                   { TDB_ERR_CORRUPT,    NT_STATUS_INTERNAL_DB_CORRUPTION },
984                   { TDB_ERR_IO,         NT_STATUS_UNEXPECTED_IO_ERROR },
985                   { TDB_ERR_OOM,        NT_STATUS_NO_MEMORY },
986                   { TDB_ERR_EXISTS,     NT_STATUS_OBJECT_NAME_COLLISION },
987
988                   /*
989                    * TDB_ERR_LOCK is very broad, we could for example
990                    * distinguish between fcntl locks and invalid lock
991                    * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
992                    * compromise.
993                    */
994                   { TDB_ERR_LOCK,       NT_STATUS_FILE_LOCK_CONFLICT },
995                   /*
996                    * The next two ones in the enum are not actually used
997                    */
998                   { TDB_ERR_NOLOCK,     NT_STATUS_FILE_LOCK_CONFLICT },
999                   { TDB_ERR_LOCK_TIMEOUT, NT_STATUS_FILE_LOCK_CONFLICT },
1000                   { TDB_ERR_NOEXIST,    NT_STATUS_NOT_FOUND },
1001                   { TDB_ERR_EINVAL,     NT_STATUS_INVALID_PARAMETER },
1002                   { TDB_ERR_RDONLY,     NT_STATUS_ACCESS_DENIED }
1003                 };
1004
1005         int i;
1006
1007         for (i=0; i < sizeof(map) / sizeof(map[0]); i++) {
1008                 if (err == map[i].err) {
1009                         return map[i].status;
1010                 }
1011         }
1012
1013         return NT_STATUS_INTERNAL_ERROR;
1014 }
1015
1016
1017 /*********************************************************************
1018  * the following is a generic validation mechanism for tdbs.
1019  *********************************************************************/
1020
1021 /* 
1022  * internal validation function, executed by the child.  
1023  */
1024 static int tdb_validate_child(struct tdb_context *tdb,
1025                               tdb_validate_data_func validate_fn)
1026 {
1027         int ret = 1;
1028         int num_entries = 0;
1029         struct tdb_validation_status v_status;
1030
1031         v_status.tdb_error = False;
1032         v_status.bad_freelist = False;
1033         v_status.bad_entry = False;
1034         v_status.unknown_key = False;
1035         v_status.success = True;
1036
1037         if (!tdb) {
1038                 v_status.tdb_error = True;
1039                 v_status.success = False;
1040                 goto out;
1041         }
1042
1043         /* Check if the tdb's freelist is good. */
1044         if (tdb_validate_freelist(tdb, &num_entries) == -1) {
1045                 v_status.bad_freelist = True;
1046                 v_status.success = False;
1047                 goto out;
1048         }
1049
1050         DEBUG(10,("tdb_validate_child: tdb %s freelist has %d entries\n",
1051                   tdb_name(tdb), num_entries));
1052
1053         /* Now traverse the tdb to validate it. */
1054         num_entries = tdb_traverse(tdb, validate_fn, (void *)&v_status);
1055         if (!v_status.success) {
1056                 goto out;
1057         } else if (num_entries == -1) {
1058                 v_status.tdb_error = True;
1059                 v_status.success = False;
1060                 goto out;
1061         }
1062
1063         DEBUG(10,("tdb_validate_child: tdb %s is good with %d entries\n",
1064                   tdb_name(tdb), num_entries));
1065         ret = 0; /* Cache is good. */
1066
1067 out:
1068         DEBUG(10,   ("tdb_validate_child: summary of validation status:\n"));
1069         DEBUGADD(10,(" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no"));
1070         DEBUGADD(10,(" * bad freelist: %s\n",v_status.bad_freelist?"yes":"no"));
1071         DEBUGADD(10,(" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no"));
1072         DEBUGADD(10,(" * unknown key: %s\n", v_status.unknown_key?"yes":"no"));
1073         DEBUGADD(10,(" => overall success: %s\n", v_status.success?"yes":"no"));
1074
1075         return ret;
1076 }
1077
1078 /*
1079  * tdb validation function.
1080  * returns 0 if tdb is ok, != 0 if it isn't.
1081  * this function expects an opened tdb.
1082  */
1083 int tdb_validate(struct tdb_context *tdb, tdb_validate_data_func validate_fn)
1084 {
1085         pid_t child_pid = -1;
1086         int child_status = 0;
1087         int wait_pid = 0;
1088         int ret = 1;
1089
1090         if (tdb == NULL) {
1091                 DEBUG(1, ("Error: tdb_validate called with tdb == NULL\n"));
1092                 return ret;
1093         }
1094
1095         DEBUG(5, ("tdb_validate called for tdb '%s'\n", tdb_name(tdb)));
1096
1097         /* fork and let the child do the validation.
1098          * benefit: no need to twist signal handlers and panic functions.
1099          * just let the child panic. we catch the signal. */
1100
1101         DEBUG(10, ("tdb_validate: forking to let child do validation.\n"));
1102         child_pid = sys_fork();
1103         if (child_pid == 0) {
1104                 /* child code */
1105                 DEBUG(10, ("tdb_validate (validation child): created\n"));
1106                 DEBUG(10, ("tdb_validate (validation child): "
1107                            "calling tdb_validate_child\n"));
1108                 exit(tdb_validate_child(tdb, validate_fn));
1109         }
1110         else if (child_pid < 0) {
1111                 DEBUG(1, ("tdb_validate: fork for validation failed.\n"));
1112                 goto done;
1113         }
1114
1115         /* parent */
1116
1117         DEBUG(10, ("tdb_validate: fork succeeded, child PID = %d\n",child_pid));
1118
1119         DEBUG(10, ("tdb_validate: waiting for child to finish...\n"));
1120         while  ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
1121                 if (errno == EINTR) {
1122                         DEBUG(10, ("tdb_validate: got signal during waitpid, "
1123                                    "retrying\n"));
1124                         errno = 0;
1125                         continue;
1126                 }
1127                 DEBUG(1, ("tdb_validate: waitpid failed with error '%s'.\n",
1128                           strerror(errno)));
1129                 goto done;
1130         }
1131         if (wait_pid != child_pid) {
1132                 DEBUG(1, ("tdb_validate: waitpid returned pid %d, "
1133                           "but %d was expected\n", wait_pid, child_pid));
1134                 goto done;
1135         }
1136
1137         DEBUG(10, ("tdb_validate: validating child returned.\n"));
1138         if (WIFEXITED(child_status)) {
1139                 DEBUG(10, ("tdb_validate: child exited, code %d.\n",
1140                            WEXITSTATUS(child_status)));
1141                 ret = WEXITSTATUS(child_status);
1142         }
1143         if (WIFSIGNALED(child_status)) {
1144                 DEBUG(10, ("tdb_validate: child terminated by signal %d\n",
1145                            WTERMSIG(child_status)));
1146 #ifdef WCOREDUMP
1147                 if (WCOREDUMP(child_status)) {
1148                         DEBUGADD(10, ("core dumped\n"));
1149                 }
1150 #endif
1151                 ret = WTERMSIG(child_status);
1152         }
1153         if (WIFSTOPPED(child_status)) {
1154                 DEBUG(10, ("tdb_validate: child was stopped by signal %d\n",
1155                            WSTOPSIG(child_status)));
1156                 ret = WSTOPSIG(child_status);
1157         }
1158
1159 done:
1160         DEBUG(5, ("tdb_validate returning code '%d' for tdb '%s'\n", ret,
1161                   tdb_name(tdb)));
1162
1163         return ret;
1164 }
1165
1166 /*
1167  * tdb validation function.
1168  * returns 0 if tdb is ok, != 0 if it isn't.
1169  * this is a wrapper around the actual validation function that opens and closes
1170  * the tdb.
1171  */
1172 int tdb_validate_open(const char *tdb_path, tdb_validate_data_func validate_fn)
1173 {
1174         TDB_CONTEXT *tdb = NULL;
1175         int ret = 1;
1176
1177         DEBUG(5, ("tdb_validate_open called for tdb '%s'\n", tdb_path));
1178
1179         tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0);
1180         if (!tdb) {
1181                 DEBUG(1, ("Error opening tdb %s\n", tdb_path));
1182                 return ret;
1183         }
1184
1185         ret = tdb_validate(tdb, validate_fn);
1186         tdb_close(tdb);
1187         return ret;
1188 }
1189
1190 /*
1191  * tdb backup function and helpers for tdb_validate wrapper with backup
1192  * handling.
1193  */
1194
1195 /* this structure eliminates the need for a global overall status for
1196  * the traverse-copy */
1197 struct tdb_copy_data {
1198         struct tdb_context *dst;
1199         bool success;
1200 };
1201
1202 static int traverse_copy_fn(struct tdb_context *tdb, TDB_DATA key,
1203                             TDB_DATA dbuf, void *private_data)
1204 {
1205         struct tdb_copy_data *data = (struct tdb_copy_data *)private_data;
1206
1207         if (tdb_store(data->dst, key, dbuf, TDB_INSERT) != 0) {
1208                 DEBUG(4, ("Failed to insert into %s: %s\n", tdb_name(data->dst),
1209                           strerror(errno)));
1210                 data->success = False;
1211                 return 1;
1212         }
1213         return 0;
1214 }
1215
1216 static int tdb_copy(struct tdb_context *src, struct tdb_context *dst)
1217 {
1218         struct tdb_copy_data data;
1219         int count;
1220
1221         data.dst = dst;
1222         data.success = True;
1223
1224         count = tdb_traverse(src, traverse_copy_fn, (void *)(&data));
1225         if ((count < 0) || (data.success == False)) {
1226                 return -1;
1227         }
1228         return count;
1229 }
1230
1231 static int tdb_verify_basic(struct tdb_context *tdb)
1232 {
1233         return tdb_traverse(tdb, NULL, NULL);
1234 }
1235
1236 /* this backup function is essentially taken from lib/tdb/tools/tdbbackup.tdb
1237  */
1238 static int tdb_backup(TALLOC_CTX *ctx, const char *src_path,
1239                       const char *dst_path, int hash_size)
1240 {
1241         struct tdb_context *src_tdb = NULL;
1242         struct tdb_context *dst_tdb = NULL;
1243         char *tmp_path = NULL;
1244         struct stat st;
1245         int count1, count2;
1246         int saved_errno = 0;
1247         int ret = -1;
1248
1249         if (stat(src_path, &st) != 0) {
1250                 DEBUG(3, ("Could not stat '%s': %s\n", src_path,
1251                           strerror(errno)));
1252                 goto done;
1253         }
1254
1255         /* open old tdb RDWR - so we can lock it */
1256         src_tdb = tdb_open_log(src_path, 0, TDB_DEFAULT, O_RDWR, 0);
1257         if (src_tdb == NULL) {
1258                 DEBUG(3, ("Failed to open tdb '%s'\n", src_path));
1259                 goto done;
1260         }
1261
1262         if (tdb_lockall(src_tdb) != 0) {
1263                 DEBUG(3, ("Failed to lock tdb '%s'\n", src_path));
1264                 goto done;
1265         }
1266
1267         tmp_path = talloc_asprintf(ctx, "%s%s", dst_path, ".tmp");
1268         unlink(tmp_path);
1269         dst_tdb = tdb_open_log(tmp_path,
1270                                hash_size ? hash_size : tdb_hash_size(src_tdb),
1271                                TDB_DEFAULT, O_RDWR | O_CREAT | O_EXCL,
1272                                st.st_mode & 0777);
1273         if (dst_tdb == NULL) {
1274                 DEBUG(3, ("Error creating tdb '%s': %s\n", tmp_path,
1275                           strerror(errno)));
1276                 saved_errno = errno;
1277                 unlink(tmp_path);
1278                 goto done;
1279         }
1280
1281         count1 = tdb_copy(src_tdb, dst_tdb);
1282         if (count1 < 0) {
1283                 DEBUG(3, ("Failed to copy tdb '%s': %s\n", src_path,
1284                           strerror(errno)));
1285                 tdb_close(dst_tdb);
1286                 goto done;
1287         }
1288
1289         /* reopen ro and do basic verification */
1290         tdb_close(dst_tdb);
1291         dst_tdb = tdb_open_log(tmp_path, 0, TDB_DEFAULT, O_RDONLY, 0);
1292         if (!dst_tdb) {
1293                 DEBUG(3, ("Failed to reopen tdb '%s': %s\n", tmp_path,
1294                           strerror(errno)));
1295                 goto done;
1296         }
1297         count2 = tdb_verify_basic(dst_tdb);
1298         if (count2 != count1) {
1299                 DEBUG(3, ("Failed to verify result of copying tdb '%s'.\n",
1300                           src_path));
1301                 tdb_close(dst_tdb);
1302                 goto done;
1303         }
1304
1305         DEBUG(10, ("tdb_backup: successfully copied %d entries\n", count1));
1306
1307         /* make sure the new tdb has reached stable storage
1308          * then rename it to its destination */
1309         fsync(tdb_fd(dst_tdb));
1310         tdb_close(dst_tdb);
1311         unlink(dst_path);
1312         if (rename(tmp_path, dst_path) != 0) {
1313                 DEBUG(3, ("Failed to rename '%s' to '%s': %s\n",
1314                           tmp_path, dst_path, strerror(errno)));
1315                 goto done;
1316         }
1317
1318         /* success */
1319         ret = 0;
1320
1321 done:
1322         if (src_tdb != NULL) {
1323                 tdb_close(src_tdb);
1324         }
1325         if (tmp_path != NULL) {
1326                 unlink(tmp_path);
1327                 TALLOC_FREE(tmp_path);
1328         }
1329         if (saved_errno != 0) {
1330                 errno = saved_errno;
1331         }
1332         return ret;
1333 }
1334
1335 static int rename_file_with_suffix(TALLOC_CTX *ctx, const char *path,
1336                                    const char *suffix)
1337 {
1338         int ret = -1;
1339         char *dst_path;
1340
1341         dst_path = talloc_asprintf(ctx, "%s%s", path, suffix);
1342
1343         ret = (rename(path, dst_path) != 0);
1344
1345         if (ret == 0) {
1346                 DEBUG(5, ("moved '%s' to '%s'\n", path, dst_path));
1347         } else if (errno == ENOENT) {
1348                 DEBUG(3, ("file '%s' does not exist - so not moved\n", path));
1349                 ret = 0;
1350         } else {
1351                 DEBUG(3, ("error renaming %s to %s: %s\n", path, dst_path,
1352                           strerror(errno)));
1353         }
1354
1355         TALLOC_FREE(dst_path);
1356         return ret;
1357 }
1358
1359 /*
1360  * do a backup of a tdb, moving the destination out of the way first
1361  */
1362 static int tdb_backup_with_rotate(TALLOC_CTX *ctx, const char *src_path,
1363                                   const char *dst_path, int hash_size,
1364                                   const char *rotate_suffix,
1365                                   bool retry_norotate_if_nospc,
1366                                   bool rename_as_last_resort_if_nospc)
1367 {
1368         int ret;
1369
1370         rename_file_with_suffix(ctx, dst_path, rotate_suffix);
1371
1372         ret = tdb_backup(ctx, src_path, dst_path, hash_size);
1373
1374         if (ret != 0) {
1375                 DEBUG(10, ("backup of %s failed: %s\n", src_path, strerror(errno)));
1376         }
1377         if ((ret != 0) && (errno == ENOSPC) && retry_norotate_if_nospc)
1378         {
1379                 char *rotate_path = talloc_asprintf(ctx, "%s%s", dst_path,
1380                                                     rotate_suffix);
1381                 DEBUG(10, ("backup of %s failed due to lack of space\n",
1382                            src_path));
1383                 DEBUGADD(10, ("trying to free some space by removing rotated "
1384                               "dst %s\n", rotate_path));
1385                 if (unlink(rotate_path) == -1) {
1386                         DEBUG(10, ("unlink of %s failed: %s\n", rotate_path,
1387                                    strerror(errno)));
1388                 } else {
1389                         ret = tdb_backup(ctx, src_path, dst_path, hash_size);
1390                 }
1391                 TALLOC_FREE(rotate_path);
1392         }
1393
1394         if ((ret != 0) && (errno == ENOSPC) && rename_as_last_resort_if_nospc)
1395         {
1396                 DEBUG(10, ("backup of %s failed due to lack of space\n", 
1397                            src_path));
1398                 DEBUGADD(10, ("using 'rename' as a last resort\n"));
1399                 ret = rename(src_path, dst_path);
1400         }
1401
1402         return ret;
1403 }
1404
1405 /*
1406  * validation function with backup handling:
1407  *
1408  *  - calls tdb_validate
1409  *  - if the tdb is ok, create a backup "name.bak", possibly moving
1410  *    existing backup to name.bak.old,
1411  *    return 0 (success) even if the backup fails
1412  *  - if the tdb is corrupt:
1413  *    - move the tdb to "name.corrupt"
1414  *    - check if there is valid backup.
1415  *      if so, restore the backup.
1416  *      if restore is successful, return 0 (success),
1417  *    - otherwise return -1 (failure)
1418  */
1419 int tdb_validate_and_backup(const char *tdb_path,
1420                             tdb_validate_data_func validate_fn)
1421 {
1422         int ret = -1;
1423         const char *backup_suffix = ".bak";
1424         const char *corrupt_suffix = ".corrupt";
1425         const char *rotate_suffix = ".old";
1426         char *tdb_path_backup;
1427         struct stat st;
1428         TALLOC_CTX *ctx = NULL;
1429
1430         ctx = talloc_new(NULL);
1431         if (ctx == NULL) {
1432                 DEBUG(0, ("tdb_validate_and_backup: out of memory\n"));
1433                 goto done;
1434         }
1435
1436         tdb_path_backup = talloc_asprintf(ctx, "%s%s", tdb_path, backup_suffix);
1437
1438         ret = tdb_validate_open(tdb_path, validate_fn);
1439
1440         if (ret == 0) {
1441                 DEBUG(1, ("tdb '%s' is valid\n", tdb_path));
1442                 ret = tdb_backup_with_rotate(ctx, tdb_path, tdb_path_backup, 0,
1443                                              rotate_suffix, True, False);
1444                 if (ret != 0) {
1445                         DEBUG(1, ("Error creating backup of tdb '%s'\n",
1446                                   tdb_path));
1447                         /* the actual validation was successful: */
1448                         ret = 0;
1449                 } else {
1450                         DEBUG(1, ("Created backup '%s' of tdb '%s'\n",
1451                                   tdb_path_backup, tdb_path));
1452                 }
1453         } else {
1454                 DEBUG(1, ("tdb '%s' is invalid\n", tdb_path));
1455
1456                 ret =stat(tdb_path_backup, &st);
1457                 if (ret != 0) {
1458                         DEBUG(5, ("Could not stat '%s': %s\n", tdb_path_backup,
1459                                   strerror(errno)));
1460                         DEBUG(1, ("No backup found.\n"));
1461                 } else {
1462                         DEBUG(1, ("backup '%s' found.\n", tdb_path_backup));
1463                         ret = tdb_validate_open(tdb_path_backup, validate_fn);
1464                         if (ret != 0) {
1465                                 DEBUG(1, ("Backup '%s' is invalid.\n",
1466                                           tdb_path_backup));
1467                         }
1468                 }
1469
1470                 if (ret != 0) {
1471                         int renamed = rename_file_with_suffix(ctx, tdb_path,
1472                                                               corrupt_suffix);
1473                         if (renamed != 0) {
1474                                 DEBUG(1, ("Error moving tdb to '%s%s'\n",
1475                                           tdb_path, corrupt_suffix));
1476                         } else {
1477                                 DEBUG(1, ("Corrupt tdb stored as '%s%s'\n",
1478                                           tdb_path, corrupt_suffix));
1479                         }
1480                         goto done;
1481                 }
1482
1483                 DEBUG(1, ("valid backup '%s' found\n", tdb_path_backup));
1484                 ret = tdb_backup_with_rotate(ctx, tdb_path_backup, tdb_path, 0,
1485                                              corrupt_suffix, True, True);
1486                 if (ret != 0) {
1487                         DEBUG(1, ("Error restoring backup from '%s'\n",
1488                                   tdb_path_backup));
1489                 } else {
1490                         DEBUG(1, ("Restored tdb backup from '%s'\n",
1491                                   tdb_path_backup));
1492                 }
1493         }
1494
1495 done:
1496         TALLOC_FREE(ctx);
1497         return ret;
1498 }