Merge commit 'release-4-0-0alpha15' into master4-tmp
[kai/samba.git] / lib / tdb_compat / tdb_compat.c
1 #include <tdb_compat.h>
2
3 /* Note: for the moment, we only need this file for TDB2, so we can
4  * assume waf. */
5 #if BUILD_TDB2
6 TDB_DATA tdb_null = { NULL, 0 };
7
8 /* Proxy which sets waitflag to false so we never block. */
9 static int lock_nonblock(int fd, int rw, off_t off, off_t len, bool waitflag,
10                          void *_orig)
11 {
12         struct tdb_attribute_flock *orig = _orig;
13
14         return orig->lock(fd, rw, off, len, false, orig->data);
15 }
16
17 enum TDB_ERROR tdb_transaction_start_nonblock(struct tdb_context *tdb)
18 {
19         union tdb_attribute locking, orig;
20         enum TDB_ERROR ecode;
21
22         orig.base.attr = TDB_ATTRIBUTE_FLOCK;
23         ecode = tdb_get_attribute(tdb, &orig);
24         if (ecode != TDB_SUCCESS)
25                 return ecode;
26
27         /* Replace locking function with our own. */
28         locking = orig;
29         locking.flock.data = &orig;
30         locking.flock.lock = lock_nonblock;
31
32         ecode = tdb_set_attribute(tdb, &locking);
33         if (ecode != TDB_SUCCESS)
34                 return ecode;
35
36         ecode = tdb_transaction_start(tdb);
37         tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
38         return ecode;
39 }
40
41 /*
42  * This handles TDB_CLEAR_IF_FIRST.
43  */
44 static enum TDB_ERROR clear_if_first(int fd, void *unused)
45 {
46         /* We hold a lock offset 63 always, so we can tell if anyone else is. */
47         struct flock fl;
48
49         fl.l_type = F_WRLCK;
50         fl.l_whence = SEEK_SET;
51         fl.l_start = 63;
52         fl.l_len = 1;
53
54         if (fcntl(fd, F_SETLK, &fl) == 0) {
55                 /* We must be first ones to open it w/ TDB_CLEAR_IF_FIRST! */
56                 if (ftruncate(fd, 0) != 0) {
57                         return TDB_ERR_IO;
58                 }
59         }
60         fl.l_type = F_RDLCK;
61         if (fcntl(fd, F_SETLKW, &fl) != 0) {
62                 return TDB_ERR_IO;
63         }
64         return TDB_SUCCESS;
65 }
66
67 struct tdb_context *
68 tdb_open_compat_(const char *name, int hash_size_unused,
69                  int tdb_flags, int open_flags, mode_t mode,
70                  void (*log_fn)(struct tdb_context *,
71                                 enum tdb_log_level,
72                                 const char *message,
73                                 void *data),
74                  void *log_data)
75 {
76         union tdb_attribute cif, log, *attr = NULL;
77
78         if (log_fn) {
79                 log.log.base.attr = TDB_ATTRIBUTE_LOG;
80                 log.log.base.next = NULL;
81                 log.log.fn = log_fn;
82                 log.log.data = log_data;
83                 attr = &log;
84         }
85
86         if (tdb_flags & TDB_CLEAR_IF_FIRST) {
87                 cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
88                 cif.openhook.base.next = attr;
89                 cif.openhook.fn = clear_if_first;
90                 attr = &cif;
91                 tdb_flags &= ~TDB_CLEAR_IF_FIRST;
92         }
93
94         /* Testsuite uses this to speed things up. */
95         if (getenv("TDB_NO_FSYNC")) {
96                 tdb_flags |= TDB_NOSYNC;
97         }
98
99         return tdb_open(name, tdb_flags|TDB_ALLOW_NESTING, open_flags, mode,
100                         attr);
101 }
102 #endif