s4:objectclass_attrs LDB module - implement the dSHeuristics length checks correctly
[kai/samba-autobuild/.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 /* For TDB1 tdbs, read traverse vs normal matters: write traverse
42    locks the entire thing! */
43 int64_t tdb_traverse_read_(struct tdb_context *tdb,
44                            int (*fn)(struct tdb_context *,
45                                                        TDB_DATA, TDB_DATA,
46                                                        void *),
47                            void *p)
48 {
49         int64_t ret;
50
51         if (tdb_get_flags(tdb) & TDB_RDONLY) {
52                 return tdb_traverse(tdb, fn, p);
53         }
54
55         tdb_add_flag(tdb, TDB_RDONLY);
56         ret = tdb_traverse(tdb, fn, p);
57         tdb_remove_flag(tdb, TDB_RDONLY);
58         return ret;
59 }
60
61 /*
62  * This handles TDB_CLEAR_IF_FIRST.
63  */
64 static enum TDB_ERROR clear_if_first(int fd, void *unused)
65 {
66         /* We hold a lock offset 4 always, so we can tell if anyone else is. */
67         struct flock fl;
68
69         fl.l_type = F_WRLCK;
70         fl.l_whence = SEEK_SET;
71         fl.l_start = 4; /* ACTIVE_LOCK */
72         fl.l_len = 1;
73
74         if (fcntl(fd, F_SETLK, &fl) == 0) {
75                 /* We must be first ones to open it w/ TDB_CLEAR_IF_FIRST! */
76                 if (ftruncate(fd, 0) != 0) {
77                         return TDB_ERR_IO;
78                 }
79         }
80         fl.l_type = F_RDLCK;
81         if (fcntl(fd, F_SETLKW, &fl) != 0) {
82                 return TDB_ERR_IO;
83         }
84         return TDB_SUCCESS;
85 }
86
87 struct tdb_context *
88 tdb_open_compat_(const char *name, int hash_size,
89                  int tdb_flags, int open_flags, mode_t mode,
90                  void (*log_fn)(struct tdb_context *,
91                                 enum tdb_log_level,
92                                 enum TDB_ERROR,
93                                 const char *message,
94                                 void *data),
95                  void *log_data)
96 {
97         union tdb_attribute cif, log, hash, max_dead, hsize, *attr = NULL;
98
99         if (!getenv("TDB_COMPAT_USE_TDB2")) {
100                 tdb_flags |= TDB_VERSION1;
101         }
102
103         if (log_fn) {
104                 log.log.base.attr = TDB_ATTRIBUTE_LOG;
105                 log.log.base.next = NULL;
106                 log.log.fn = log_fn;
107                 log.log.data = log_data;
108                 attr = &log;
109         }
110
111         if (tdb_flags & TDB_CLEAR_IF_FIRST) {
112                 cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
113                 cif.openhook.base.next = attr;
114                 cif.openhook.fn = clear_if_first;
115                 attr = &cif;
116                 tdb_flags &= ~TDB_CLEAR_IF_FIRST;
117         }
118
119         if (tdb_flags & TDB_INCOMPATIBLE_HASH) {
120                 if (tdb_flags & TDB_VERSION1) {
121                         hash.hash.base.attr = TDB_ATTRIBUTE_HASH;
122                         hash.hash.base.next = attr;
123                         hash.hash.fn = tdb1_incompatible_hash;
124                         attr = &hash;
125                 }
126                 tdb_flags &= ~TDB_INCOMPATIBLE_HASH;
127         }
128
129         if (tdb_flags & TDB_VOLATILE) {
130                 if (tdb_flags & TDB_VERSION1) {
131                         max_dead.base.attr = TDB_ATTRIBUTE_TDB1_MAX_DEAD;
132                         max_dead.base.next = attr;
133                         max_dead.tdb1_max_dead.max_dead = 5;
134                         attr = &max_dead;
135                 }
136                 tdb_flags &= ~TDB_VOLATILE;
137         }
138
139         if (hash_size && (tdb_flags & TDB_VERSION1)) {
140                 hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
141                 hsize.base.next = attr;
142                 hsize.tdb1_hashsize.hsize = hash_size;
143                 attr = &hsize;
144         }
145
146         /* Testsuite uses this to speed things up. */
147         if (getenv("TDB_NO_FSYNC")) {
148                 tdb_flags |= TDB_NOSYNC;
149         }
150
151         return tdb_open(name, tdb_flags|TDB_ALLOW_NESTING, open_flags, mode,
152                         attr);
153 }
154
155 /* We only need these for the CLEAR_IF_FIRST lock. */
156 static int reacquire_cif_lock(struct tdb_context *tdb, bool *fail)
157 {
158         struct flock fl;
159         union tdb_attribute cif;
160
161         cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
162         cif.openhook.base.next = NULL;
163
164         if (tdb_get_attribute(tdb, &cif) != TDB_SUCCESS
165             || cif.openhook.fn != clear_if_first) {
166                 return 0;
167         }
168
169         /* We hold a lock offset 4 always, so we can tell if anyone else is. */
170         fl.l_type = F_RDLCK;
171         fl.l_whence = SEEK_SET;
172         fl.l_start = 4; /* ACTIVE_LOCK */
173         fl.l_len = 1;
174         if (fcntl(tdb_fd(tdb), F_SETLKW, &fl) != 0) {
175                 *fail = true;
176                 return -1;
177         }
178         return 0;
179 }
180
181 int tdb_reopen(struct tdb_context *tdb)
182 {
183         bool unused;
184         return reacquire_cif_lock(tdb, &unused);
185 }
186
187 int tdb_reopen_all(int parent_longlived)
188 {
189         bool fail = false;
190
191         if (parent_longlived) {
192                 return 0;
193         }
194
195         tdb_foreach(reacquire_cif_lock, &fail);
196         if (fail)
197                 return -1;
198         return 0;
199 }
200 #endif