Fix bug #8807 - dcerpc_lsa_lookup_sids_noalloc() crashes when groups has more than...
[Samba/gebeck_regimport.git] / lib / tdb_compat / tdb_compat.c
blob0406eff55e4d0b33d798d41c11fb218a18bef451
1 #include <tdb_compat.h>
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 };
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)
12 struct tdb_attribute_flock *orig = _orig;
14 return orig->lock(fd, rw, off, len, false, orig->data);
17 enum TDB_ERROR tdb_transaction_start_nonblock(struct tdb_context *tdb)
19 union tdb_attribute locking, orig;
20 enum TDB_ERROR ecode;
22 orig.base.attr = TDB_ATTRIBUTE_FLOCK;
23 ecode = tdb_get_attribute(tdb, &orig);
24 if (ecode != TDB_SUCCESS)
25 return ecode;
27 /* Replace locking function with our own. */
28 locking = orig;
29 locking.flock.data = &orig;
30 locking.flock.lock = lock_nonblock;
32 ecode = tdb_set_attribute(tdb, &locking);
33 if (ecode != TDB_SUCCESS)
34 return ecode;
36 ecode = tdb_transaction_start(tdb);
37 tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
38 return ecode;
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)
49 int64_t ret;
51 if (tdb_get_flags(tdb) & TDB_RDONLY) {
52 return tdb_traverse(tdb, fn, p);
55 tdb_add_flag(tdb, TDB_RDONLY);
56 ret = tdb_traverse(tdb, fn, p);
57 tdb_remove_flag(tdb, TDB_RDONLY);
58 return ret;
62 * This handles TDB_CLEAR_IF_FIRST.
64 static enum TDB_ERROR clear_if_first(int fd, void *unused)
66 /* We hold a lock offset 4 always, so we can tell if anyone else is. */
67 struct flock fl;
69 fl.l_type = F_WRLCK;
70 fl.l_whence = SEEK_SET;
71 fl.l_start = 4; /* ACTIVE_LOCK */
72 fl.l_len = 1;
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;
80 fl.l_type = F_RDLCK;
81 if (fcntl(fd, F_SETLKW, &fl) != 0) {
82 return TDB_ERR_IO;
84 return TDB_SUCCESS;
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)
97 union tdb_attribute cif, log, hash, max_dead, hsize, *attr = NULL;
99 if (!getenv("TDB_COMPAT_USE_TDB2")) {
100 tdb_flags |= TDB_VERSION1;
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;
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;
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;
126 tdb_flags &= ~TDB_INCOMPATIBLE_HASH;
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;
136 tdb_flags &= ~TDB_VOLATILE;
139 if (hash_size && (tdb_flags & TDB_VERSION1) && (open_flags & O_CREAT)) {
140 hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
141 hsize.base.next = attr;
142 hsize.tdb1_hashsize.hsize = hash_size;
143 attr = &hsize;
146 /* Testsuite uses this to speed things up. */
147 if (getenv("TDB_NO_FSYNC")) {
148 tdb_flags |= TDB_NOSYNC;
151 return tdb_open(name, tdb_flags|TDB_ALLOW_NESTING, open_flags, mode,
152 attr);
155 /* We only need these for the CLEAR_IF_FIRST lock. */
156 static int reacquire_cif_lock(struct tdb_context *tdb, bool *fail)
158 struct flock fl;
159 union tdb_attribute cif;
161 cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
162 cif.openhook.base.next = NULL;
164 if (tdb_get_attribute(tdb, &cif) != TDB_SUCCESS
165 || cif.openhook.fn != clear_if_first) {
166 return 0;
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;
178 return 0;
181 int tdb_reopen(struct tdb_context *tdb)
183 bool unused;
184 return reacquire_cif_lock(tdb, &unused);
187 int tdb_reopen_all(int parent_longlived)
189 bool fail = false;
191 if (parent_longlived) {
192 return 0;
195 tdb_foreach(reacquire_cif_lock, &fail);
196 if (fail)
197 return -1;
198 return 0;
200 #endif