s3:smb2_break: make use of file_fsp_smb2()
[Samba/gebeck_regimport.git] / lib / tdb_compat / tdb_compat.c
blob7fd3caf6b5acc53a930b3a1471efaea45b4cabb1
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 enum TDB_ERROR tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
43 union tdb_attribute locking, orig;
44 enum TDB_ERROR ecode;
46 orig.base.attr = TDB_ATTRIBUTE_FLOCK;
47 ecode = tdb_get_attribute(tdb, &orig);
48 if (ecode != TDB_SUCCESS)
49 return ecode;
51 /* Replace locking function with our own. */
52 locking = orig;
53 locking.flock.data = &orig;
54 locking.flock.lock = lock_nonblock;
56 ecode = tdb_set_attribute(tdb, &locking);
57 if (ecode != TDB_SUCCESS)
58 return ecode;
60 ecode = tdb_chainlock(tdb, key);
61 tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
62 return ecode;
65 /* For TDB1 tdbs, read traverse vs normal matters: write traverse
66 locks the entire thing! */
67 int64_t tdb_traverse_read_(struct tdb_context *tdb,
68 int (*fn)(struct tdb_context *,
69 TDB_DATA, TDB_DATA,
70 void *),
71 void *p)
73 int64_t ret;
75 if (tdb_get_flags(tdb) & TDB_RDONLY) {
76 return tdb_traverse(tdb, fn, p);
79 tdb_add_flag(tdb, TDB_RDONLY);
80 ret = tdb_traverse(tdb, fn, p);
81 tdb_remove_flag(tdb, TDB_RDONLY);
82 return ret;
86 * This handles TDB_CLEAR_IF_FIRST.
88 static enum TDB_ERROR clear_if_first(int fd, void *unused)
90 /* We hold a lock offset 4 always, so we can tell if anyone else is. */
91 struct flock fl;
93 fl.l_type = F_WRLCK;
94 fl.l_whence = SEEK_SET;
95 fl.l_start = 4; /* ACTIVE_LOCK */
96 fl.l_len = 1;
98 if (fcntl(fd, F_SETLK, &fl) == 0) {
99 /* We must be first ones to open it w/ TDB_CLEAR_IF_FIRST! */
100 if (ftruncate(fd, 0) != 0) {
101 return TDB_ERR_IO;
104 fl.l_type = F_RDLCK;
105 if (fcntl(fd, F_SETLKW, &fl) != 0) {
106 return TDB_ERR_IO;
108 return TDB_SUCCESS;
111 struct tdb_context *
112 tdb_open_compat_(const char *name, int hash_size,
113 int tdb_flags, int open_flags, mode_t mode,
114 void (*log_fn)(struct tdb_context *,
115 enum tdb_log_level,
116 enum TDB_ERROR,
117 const char *message,
118 void *data),
119 void *log_data)
121 union tdb_attribute cif, log, hash, max_dead, hsize, *attr = NULL;
123 if (!getenv("TDB_COMPAT_USE_TDB2")) {
124 tdb_flags |= TDB_VERSION1;
127 if (log_fn) {
128 log.log.base.attr = TDB_ATTRIBUTE_LOG;
129 log.log.base.next = NULL;
130 log.log.fn = log_fn;
131 log.log.data = log_data;
132 attr = &log;
135 if (tdb_flags & TDB_CLEAR_IF_FIRST) {
136 cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
137 cif.openhook.base.next = attr;
138 cif.openhook.fn = clear_if_first;
139 attr = &cif;
140 tdb_flags &= ~TDB_CLEAR_IF_FIRST;
143 if (tdb_flags & TDB_INCOMPATIBLE_HASH) {
144 if (tdb_flags & TDB_VERSION1) {
145 hash.hash.base.attr = TDB_ATTRIBUTE_HASH;
146 hash.hash.base.next = attr;
147 hash.hash.fn = tdb1_incompatible_hash;
148 attr = &hash;
150 tdb_flags &= ~TDB_INCOMPATIBLE_HASH;
153 if (tdb_flags & TDB_VOLATILE) {
154 if (tdb_flags & TDB_VERSION1) {
155 max_dead.base.attr = TDB_ATTRIBUTE_TDB1_MAX_DEAD;
156 max_dead.base.next = attr;
157 max_dead.tdb1_max_dead.max_dead = 5;
158 attr = &max_dead;
160 tdb_flags &= ~TDB_VOLATILE;
163 if (hash_size && (tdb_flags & TDB_VERSION1) && (open_flags & O_CREAT)) {
164 hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
165 hsize.base.next = attr;
166 hsize.tdb1_hashsize.hsize = hash_size;
167 attr = &hsize;
170 /* Testsuite uses this to speed things up. */
171 if (getenv("TDB_NO_FSYNC")) {
172 tdb_flags |= TDB_NOSYNC;
175 return tdb_open(name, tdb_flags|TDB_ALLOW_NESTING, open_flags, mode,
176 attr);
179 /* We only need these for the CLEAR_IF_FIRST lock. */
180 static int reacquire_cif_lock(struct tdb_context *tdb, bool *fail)
182 struct flock fl;
183 union tdb_attribute cif;
185 cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
186 cif.openhook.base.next = NULL;
188 if (tdb_get_attribute(tdb, &cif) != TDB_SUCCESS
189 || cif.openhook.fn != clear_if_first) {
190 return 0;
193 /* We hold a lock offset 4 always, so we can tell if anyone else is. */
194 fl.l_type = F_RDLCK;
195 fl.l_whence = SEEK_SET;
196 fl.l_start = 4; /* ACTIVE_LOCK */
197 fl.l_len = 1;
198 if (fcntl(tdb_fd(tdb), F_SETLKW, &fl) != 0) {
199 *fail = true;
200 return -1;
202 return 0;
205 int tdb_reopen(struct tdb_context *tdb)
207 bool unused;
208 return reacquire_cif_lock(tdb, &unused);
211 int tdb_reopen_all(int parent_longlived)
213 bool fail = false;
215 if (parent_longlived) {
216 return 0;
219 tdb_foreach(reacquire_cif_lock, &fail);
220 if (fail)
221 return -1;
222 return 0;
224 #endif