preparing for release of alpha.0.6
[Samba.git] / source / locking / brlock.c
blob71fc45854a69e50f5e134398aae4f0b1b50fbc2a
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 byte range locking code
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* this module implements a tdb based byte range locking service,
23 replacing the fcntl() based byte range locking previously
24 used. This allows us to provide the same semantics as NT */
26 #include "includes.h"
28 extern int DEBUGLEVEL;
30 /* this contains elements that differentiate locks. The smbpid is a
31 client supplied pid, and is essentially the locking context for
32 this client */
33 struct lock_context {
34 uint16 smbpid;
35 uint16 tid;
36 pid_t pid;
39 /* the data in brlock records is an unsorted linear array of these
40 records. It is unnecessary to store the count as tdb provides the
41 size of the record */
42 struct lock_struct {
43 struct lock_context context;
44 br_off start;
45 br_off size;
46 int fnum;
47 enum brl_type lock_type;
50 /* the key used in the brlock database */
51 struct lock_key {
52 SMB_DEV_T device;
53 SMB_INO_T inode;
56 /* the open brlock.tdb database */
57 static TDB_CONTEXT *tdb;
60 /****************************************************************************
61 see if two locking contexts are equal
62 ****************************************************************************/
63 static BOOL brl_same_context(struct lock_context *ctx1,
64 struct lock_context *ctx2)
66 return (ctx1->pid == ctx2->pid) &&
67 (ctx1->smbpid == ctx2->smbpid) &&
68 (ctx1->tid == ctx2->tid);
71 /****************************************************************************
72 see if lock2 can be added when lock1 is in place
73 ****************************************************************************/
74 static BOOL brl_conflict(struct lock_struct *lck1,
75 struct lock_struct *lck2)
77 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
78 return False;
80 if (brl_same_context(&lck1->context, &lck2->context) &&
81 lck2->lock_type == READ_LOCK) return False;
83 if (lck1->start >= (lck2->start + lck2->size) ||
84 lck2->start >= (lck1->start + lck1->size)) return False;
86 return True;
90 /****************************************************************************
91 open up the brlock.tdb database
92 ****************************************************************************/
93 void brl_init(int read_only)
95 if (tdb) return;
96 tdb = tdb_open(lock_path("brlock.tdb"), 0, TDB_CLEAR_IF_FIRST,
97 read_only?O_RDONLY:O_RDWR|O_CREAT, 0644);
98 if (!tdb) {
99 DEBUG(0,("Failed to open byte range locking database\n"));
104 /****************************************************************************
105 lock a range of bytes
106 ****************************************************************************/
107 BOOL brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
108 uint16 smbpid, pid_t pid, uint16 tid,
109 br_off start, br_off size,
110 enum brl_type lock_type)
112 struct lock_key key;
113 TDB_DATA kbuf, dbuf;
114 int count, i;
115 struct lock_struct lock, *locks;
117 key.device = dev;
118 key.inode = ino;
119 kbuf.dptr = (char *)&key;
120 kbuf.dsize = sizeof(key);
122 dbuf.dptr = NULL;
124 tdb_lockchain(tdb, kbuf);
125 dbuf = tdb_fetch(tdb, kbuf);
127 lock.context.smbpid = smbpid;
128 lock.context.pid = pid;
129 lock.context.tid = tid;
130 lock.start = start;
131 lock.size = size;
132 lock.fnum = fnum;
133 lock.lock_type = lock_type;
135 if (dbuf.dptr) {
136 /* there are existing locks - make sure they don't conflict */
137 locks = (struct lock_struct *)dbuf.dptr;
138 count = dbuf.dsize / sizeof(*locks);
139 for (i=0; i<count; i++) {
140 if (brl_conflict(&locks[i], &lock)) {
141 goto fail;
146 /* no conflicts - add it to the list of locks */
147 dbuf.dptr = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
148 if (!dbuf.dptr) goto fail;
149 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
150 dbuf.dsize += sizeof(lock);
151 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
153 free(dbuf.dptr);
154 tdb_unlockchain(tdb, kbuf);
155 return True;
157 fail:
158 if (dbuf.dptr) free(dbuf.dptr);
159 tdb_unlockchain(tdb, kbuf);
160 return False;
164 /****************************************************************************
165 unlock a range of bytes
166 ****************************************************************************/
167 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
168 uint16 smbpid, pid_t pid, uint16 tid,
169 br_off start, br_off size)
171 struct lock_key key;
172 TDB_DATA kbuf, dbuf;
173 int count, i;
174 struct lock_struct *locks;
175 struct lock_context context;
177 key.device = dev;
178 key.inode = ino;
179 kbuf.dptr = (char *)&key;
180 kbuf.dsize = sizeof(key);
182 dbuf.dptr = NULL;
184 tdb_lockchain(tdb, kbuf);
185 dbuf = tdb_fetch(tdb, kbuf);
187 if (!dbuf.dptr) goto fail;
189 context.smbpid = smbpid;
190 context.pid = pid;
191 context.tid = tid;
193 /* there are existing locks - find a match */
194 locks = (struct lock_struct *)dbuf.dptr;
195 count = dbuf.dsize / sizeof(*locks);
196 for (i=0; i<count; i++) {
197 if (brl_same_context(&locks[i].context, &context) &&
198 locks[i].fnum == fnum &&
199 locks[i].start == start &&
200 locks[i].size == size) {
201 /* found it - delete it */
202 if (count == 1) {
203 tdb_delete(tdb, kbuf);
204 } else {
205 if (i < count-1) {
206 memmove(&locks[i], &locks[i+1],
207 sizeof(*locks)*((count-1) - i));
209 dbuf.dsize -= sizeof(*locks);
210 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
213 free(dbuf.dptr);
214 tdb_unlockchain(tdb, kbuf);
215 return True;
219 /* we didn't find it */
221 fail:
222 if (dbuf.dptr) free(dbuf.dptr);
223 tdb_unlockchain(tdb, kbuf);
224 return False;
229 /****************************************************************************
230 test if we could add a lock if we wanted to
231 ****************************************************************************/
232 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino,
233 uint16 smbpid, pid_t pid, uint16 tid,
234 br_off start, br_off size,
235 enum brl_type lock_type)
237 struct lock_key key;
238 TDB_DATA kbuf, dbuf;
239 int count, i;
240 struct lock_struct lock, *locks;
242 key.device = dev;
243 key.inode = ino;
244 kbuf.dptr = (char *)&key;
245 kbuf.dsize = sizeof(key);
247 dbuf.dptr = NULL;
249 tdb_lockchain(tdb, kbuf);
250 dbuf = tdb_fetch(tdb, kbuf);
252 lock.context.smbpid = smbpid;
253 lock.context.pid = pid;
254 lock.context.tid = tid;
255 lock.start = start;
256 lock.size = size;
257 lock.lock_type = lock_type;
259 if (dbuf.dptr) {
260 /* there are existing locks - make sure they don't conflict */
261 locks = (struct lock_struct *)dbuf.dptr;
262 count = dbuf.dsize / sizeof(*locks);
263 for (i=0; i<count; i++) {
264 if (brl_conflict(&locks[i], &lock)) {
265 goto fail;
270 /* no conflicts - we could have added it */
271 free(dbuf.dptr);
272 tdb_unlockchain(tdb, kbuf);
273 return True;
275 fail:
276 if (dbuf.dptr) free(dbuf.dptr);
277 tdb_unlockchain(tdb, kbuf);
278 return False;
282 /****************************************************************************
283 remove any locks associated with a open file
284 ****************************************************************************/
285 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
287 struct lock_key key;
288 TDB_DATA kbuf, dbuf;
289 int count, i;
290 struct lock_struct *locks;
292 key.device = dev;
293 key.inode = ino;
294 kbuf.dptr = (char *)&key;
295 kbuf.dsize = sizeof(key);
297 dbuf.dptr = NULL;
299 tdb_lockchain(tdb, kbuf);
300 dbuf = tdb_fetch(tdb, kbuf);
302 if (!dbuf.dptr) goto fail;
304 /* there are existing locks - remove any for this fnum */
305 locks = (struct lock_struct *)dbuf.dptr;
306 count = dbuf.dsize / sizeof(*locks);
307 for (i=0; i<count; i++) {
308 if (locks[i].context.tid == tid &&
309 locks[i].context.pid == pid &&
310 locks[i].fnum == fnum) {
311 /* found it - delete it */
312 if (count > 1 && i < count-1) {
313 memmove(&locks[i], &locks[i+1],
314 sizeof(*locks)*((count-1) - i));
316 count--;
317 i--;
321 if (count == 0) {
322 tdb_delete(tdb, kbuf);
323 } else if (count < (dbuf.dsize / sizeof(*locks))) {
324 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
327 /* we didn't find it */
328 fail:
329 if (dbuf.dptr) free(dbuf.dptr);
330 tdb_unlockchain(tdb, kbuf);
334 /****************************************************************************
335 traverse the whole database with this function, calling traverse_callback
336 on each lock
337 ****************************************************************************/
338 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
340 struct lock_struct *locks;
341 struct lock_key *key;
342 int i;
344 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
346 locks = (struct lock_struct *)dbuf.dptr;
347 key = (struct lock_key *)kbuf.dptr;
349 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
350 traverse_callback(key->device, key->inode,
351 locks[i].context.pid,
352 locks[i].lock_type,
353 locks[i].start,
354 locks[i].size);
356 return 0;
359 /*******************************************************************
360 Call the specified function on each lock in the database
361 ********************************************************************/
362 int brl_forall(BRLOCK_FN(fn))
364 if (!tdb) return 0;
365 return tdb_traverse(tdb, traverse_fn, (BRLOCK_FN_CAST())fn);