this now works as a add|delete share command :-)
[Samba.git] / source / locking / brlock.c
blob175ab5c9b0a62b2ce78207080420db5fc21625df
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 byte range locking code
5 Updated to handle range splits/merges.
7 Copyright (C) Andrew Tridgell 1992-2000
8 Copyright (C) Jeremy Allison 1992-2000
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* This module implements a tdb based byte range locking service,
26 replacing the fcntl() based byte range locking previously
27 used. This allows us to provide the same semantics as NT */
29 #include "includes.h"
31 extern int DEBUGLEVEL;
33 /* This contains elements that differentiate locks. The smbpid is a
34 client supplied pid, and is essentially the locking context for
35 this client */
37 struct lock_context {
38 uint16 smbpid;
39 uint16 tid;
40 pid_t pid;
43 /* The data in brlock records is an unsorted linear array of these
44 records. It is unnecessary to store the count as tdb provides the
45 size of the record */
47 struct lock_struct {
48 struct lock_context context;
49 br_off start;
50 br_off size;
51 int fnum;
52 enum brl_type lock_type;
55 /* The key used in the brlock database. */
57 struct lock_key {
58 SMB_DEV_T device;
59 SMB_INO_T inode;
62 /* The open brlock.tdb database. */
64 static TDB_CONTEXT *tdb;
66 /****************************************************************************
67 Create a locking key - ensuring zero filled for pad purposes.
68 ****************************************************************************/
70 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
72 static struct lock_key key;
73 TDB_DATA kbuf;
75 memset(&key, '\0', sizeof(key));
76 key.device = dev;
77 key.inode = inode;
78 kbuf.dptr = (char *)&key;
79 kbuf.dsize = sizeof(key);
80 return kbuf;
83 /****************************************************************************
84 See if two locking contexts are equal.
85 ****************************************************************************/
87 static BOOL brl_same_context(struct lock_context *ctx1,
88 struct lock_context *ctx2)
90 return (ctx1->pid == ctx2->pid) &&
91 (ctx1->smbpid == ctx2->smbpid) &&
92 (ctx1->tid == ctx2->tid);
95 /****************************************************************************
96 See if lock2 can be added when lock1 is in place.
97 ****************************************************************************/
99 static BOOL brl_conflict(struct lock_struct *lck1,
100 struct lock_struct *lck2)
102 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
103 return False;
105 if (brl_same_context(&lck1->context, &lck2->context) &&
106 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) return False;
108 if (lck1->start >= (lck2->start + lck2->size) ||
109 lck2->start >= (lck1->start + lck1->size)) return False;
111 return True;
115 /****************************************************************************
116 delete a record if it is for a dead process
117 ****************************************************************************/
118 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
120 struct lock_struct *locks;
121 int count, i;
123 tdb_chainlock(tdb, kbuf);
125 locks = (struct lock_struct *)dbuf.dptr;
127 count = dbuf.dsize / sizeof(*locks);
128 for (i=0; i<count; i++) {
129 struct lock_struct *lock = &locks[i];
131 if (process_exists(lock->context.pid)) continue;
133 if (count > 1 && i < count-1) {
134 memmove(&locks[i], &locks[i+1],
135 sizeof(*locks)*((count-1) - i));
137 count--;
138 i--;
141 if (count == 0) {
142 tdb_delete(tdb, kbuf);
143 } else if (count < (dbuf.dsize / sizeof(*locks))) {
144 dbuf.dsize = count * sizeof(*locks);
145 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
148 tdb_chainunlock(tdb, kbuf);
149 return 0;
152 /****************************************************************************
153 Open up the brlock.tdb database.
154 ****************************************************************************/
155 void brl_init(int read_only)
157 if (tdb) return;
158 tdb = tdb_open(lock_path("brlock.tdb"), 0, TDB_CLEAR_IF_FIRST,
159 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
160 if (!tdb) {
161 DEBUG(0,("Failed to open byte range locking database\n"));
162 return;
165 /* delete any dead locks */
166 if (!read_only) {
167 tdb_traverse(tdb, delete_fn, NULL);
172 /****************************************************************************
173 Lock a range of bytes.
174 ****************************************************************************/
176 BOOL brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
177 uint16 smbpid, pid_t pid, uint16 tid,
178 br_off start, br_off size,
179 enum brl_type lock_type)
181 TDB_DATA kbuf, dbuf;
182 int count, i;
183 struct lock_struct lock, *locks;
185 kbuf = locking_key(dev,ino);
187 dbuf.dptr = NULL;
189 tdb_chainlock(tdb, kbuf);
190 dbuf = tdb_fetch(tdb, kbuf);
192 lock.context.smbpid = smbpid;
193 lock.context.pid = pid;
194 lock.context.tid = tid;
195 lock.start = start;
196 lock.size = size;
197 lock.fnum = fnum;
198 lock.lock_type = lock_type;
200 if (dbuf.dptr) {
201 /* there are existing locks - make sure they don't conflict */
202 locks = (struct lock_struct *)dbuf.dptr;
203 count = dbuf.dsize / sizeof(*locks);
204 for (i=0; i<count; i++) {
205 if (brl_conflict(&locks[i], &lock)) {
206 goto fail;
211 /* no conflicts - add it to the list of locks */
212 dbuf.dptr = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
213 if (!dbuf.dptr) goto fail;
214 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
215 dbuf.dsize += sizeof(lock);
216 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
218 free(dbuf.dptr);
219 tdb_chainunlock(tdb, kbuf);
220 return True;
222 fail:
223 if (dbuf.dptr) free(dbuf.dptr);
224 tdb_chainunlock(tdb, kbuf);
225 return False;
228 /****************************************************************************
229 Unlock a range of bytes.
230 ****************************************************************************/
232 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
233 uint16 smbpid, pid_t pid, uint16 tid,
234 br_off start, br_off size)
236 TDB_DATA kbuf, dbuf;
237 int count, i;
238 struct lock_struct *locks;
239 struct lock_context context;
241 kbuf = locking_key(dev,ino);
243 dbuf.dptr = NULL;
245 tdb_chainlock(tdb, kbuf);
246 dbuf = tdb_fetch(tdb, kbuf);
248 if (!dbuf.dptr) {
249 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
250 goto fail;
253 context.smbpid = smbpid;
254 context.pid = pid;
255 context.tid = tid;
257 /* there are existing locks - find a match */
258 locks = (struct lock_struct *)dbuf.dptr;
259 count = dbuf.dsize / sizeof(*locks);
260 for (i=0; i<count; i++) {
262 struct lock_struct *lock = &locks[i];
264 #if 0
265 /* JRATEST - DEBUGGING INFO */
266 if(!brl_same_context(&lock->context, &context)) {
267 DEBUG(10,("brl_unlock: Not same context. l_smbpid = %u, l_pid = %u, l_tid = %u: \
268 smbpid = %u, pid = %u, tid = %u\n",
269 lock->context.smbpid, lock->context.pid, lock->context.tid,
270 context.smbpid, context.pid, context.tid ));
273 /* JRATEST */
274 #endif
276 if (brl_same_context(&lock->context, &context) &&
277 lock->fnum == fnum &&
278 lock->start == start &&
279 lock->size == size) {
280 /* found it - delete it */
281 if (count == 1) {
282 tdb_delete(tdb, kbuf);
283 } else {
284 if (i < count-1) {
285 memmove(&locks[i], &locks[i+1],
286 sizeof(*locks)*((count-1) - i));
288 dbuf.dsize -= sizeof(*locks);
289 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
292 free(dbuf.dptr);
293 tdb_chainunlock(tdb, kbuf);
294 return True;
298 /* we didn't find it */
300 fail:
301 if (dbuf.dptr) free(dbuf.dptr);
302 tdb_chainunlock(tdb, kbuf);
303 return False;
306 /****************************************************************************
307 Test if we could add a lock if we wanted to.
308 ****************************************************************************/
310 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
311 uint16 smbpid, pid_t pid, uint16 tid,
312 br_off start, br_off size,
313 enum brl_type lock_type)
315 TDB_DATA kbuf, dbuf;
316 int count, i;
317 struct lock_struct lock, *locks;
319 kbuf = locking_key(dev,ino);
321 dbuf.dptr = NULL;
323 tdb_chainlock(tdb, kbuf);
324 dbuf = tdb_fetch(tdb, kbuf);
326 lock.context.smbpid = smbpid;
327 lock.context.pid = pid;
328 lock.context.tid = tid;
329 lock.start = start;
330 lock.size = size;
331 lock.fnum = fnum;
332 lock.lock_type = lock_type;
334 if (dbuf.dptr) {
335 /* there are existing locks - make sure they don't conflict */
336 locks = (struct lock_struct *)dbuf.dptr;
337 count = dbuf.dsize / sizeof(*locks);
338 for (i=0; i<count; i++) {
339 if (brl_conflict(&locks[i], &lock)) {
340 goto fail;
345 /* no conflicts - we could have added it */
346 free(dbuf.dptr);
347 tdb_chainunlock(tdb, kbuf);
348 return True;
350 fail:
351 if (dbuf.dptr) free(dbuf.dptr);
352 tdb_chainunlock(tdb, kbuf);
353 return False;
356 /****************************************************************************
357 Remove any locks associated with a open file.
358 ****************************************************************************/
360 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
362 TDB_DATA kbuf, dbuf;
363 int count, i, dcount=0;
364 struct lock_struct *locks;
366 kbuf = locking_key(dev,ino);
368 dbuf.dptr = NULL;
370 tdb_chainlock(tdb, kbuf);
371 dbuf = tdb_fetch(tdb, kbuf);
373 if (!dbuf.dptr) goto fail;
375 /* there are existing locks - remove any for this fnum */
376 locks = (struct lock_struct *)dbuf.dptr;
377 count = dbuf.dsize / sizeof(*locks);
378 for (i=0; i<count; i++) {
379 struct lock_struct *lock = &locks[i];
381 if (lock->context.tid == tid &&
382 lock->context.pid == pid &&
383 lock->fnum == fnum) {
384 /* found it - delete it */
385 if (count > 1 && i < count-1) {
386 memmove(&locks[i], &locks[i+1],
387 sizeof(*locks)*((count-1) - i));
389 count--;
390 i--;
391 dcount++;
395 if (count == 0) {
396 tdb_delete(tdb, kbuf);
397 } else if (count < (dbuf.dsize / sizeof(*locks))) {
398 dbuf.dsize -= dcount * sizeof(*locks);
399 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
402 /* we didn't find it */
403 fail:
404 if (dbuf.dptr) free(dbuf.dptr);
405 tdb_chainunlock(tdb, kbuf);
408 /****************************************************************************
409 Traverse the whole database with this function, calling traverse_callback
410 on each lock.
411 ****************************************************************************/
413 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
415 struct lock_struct *locks;
416 struct lock_key *key;
417 int i;
419 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
421 locks = (struct lock_struct *)dbuf.dptr;
422 key = (struct lock_key *)kbuf.dptr;
424 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
425 traverse_callback(key->device, key->inode,
426 locks[i].context.pid,
427 locks[i].lock_type,
428 locks[i].start,
429 locks[i].size);
431 return 0;
434 /*******************************************************************
435 Call the specified function on each lock in the database.
436 ********************************************************************/
438 int brl_forall(BRLOCK_FN(fn))
440 if (!tdb) return 0;
441 return tdb_traverse(tdb, traverse_fn, (void *)fn);