2 Unix SMB/Netbios implementation.
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 */
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
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
43 struct lock_context context
;
47 enum brl_type lock_type
;
50 /* the key used in the brlock database */
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
)
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
;
90 /****************************************************************************
91 open up the brlock.tdb database
92 ****************************************************************************/
93 void brl_init(int read_only
)
96 tdb
= tdb_open(lock_path("brlock.tdb"), 0, TDB_CLEAR_IF_FIRST
,
97 read_only
?O_RDONLY
:O_RDWR
|O_CREAT
, 0644);
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
)
115 struct lock_struct lock
, *locks
;
119 kbuf
.dptr
= (char *)&key
;
120 kbuf
.dsize
= sizeof(key
);
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
;
133 lock
.lock_type
= lock_type
;
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
)) {
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
);
154 tdb_unlockchain(tdb
, kbuf
);
158 if (dbuf
.dptr
) free(dbuf
.dptr
);
159 tdb_unlockchain(tdb
, kbuf
);
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
)
174 struct lock_struct
*locks
;
175 struct lock_context context
;
179 kbuf
.dptr
= (char *)&key
;
180 kbuf
.dsize
= sizeof(key
);
184 tdb_lockchain(tdb
, kbuf
);
185 dbuf
= tdb_fetch(tdb
, kbuf
);
187 if (!dbuf
.dptr
) goto fail
;
189 context
.smbpid
= smbpid
;
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 */
203 tdb_delete(tdb
, kbuf
);
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
);
214 tdb_unlockchain(tdb
, kbuf
);
219 /* we didn't find it */
222 if (dbuf
.dptr
) free(dbuf
.dptr
);
223 tdb_unlockchain(tdb
, kbuf
);
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
)
240 struct lock_struct lock
, *locks
;
244 kbuf
.dptr
= (char *)&key
;
245 kbuf
.dsize
= sizeof(key
);
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
;
257 lock
.lock_type
= lock_type
;
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
)) {
270 /* no conflicts - we could have added it */
272 tdb_unlockchain(tdb
, kbuf
);
276 if (dbuf
.dptr
) free(dbuf
.dptr
);
277 tdb_unlockchain(tdb
, kbuf
);
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
)
290 struct lock_struct
*locks
;
294 kbuf
.dptr
= (char *)&key
;
295 kbuf
.dsize
= sizeof(key
);
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
));
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 */
329 if (dbuf
.dptr
) free(dbuf
.dptr
);
330 tdb_unlockchain(tdb
, kbuf
);
334 /****************************************************************************
335 traverse the whole database with this function, calling traverse_callback
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
;
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
,
359 /*******************************************************************
360 Call the specified function on each lock in the database
361 ********************************************************************/
362 int brl_forall(BRLOCK_FN(fn
))
365 return tdb_traverse(tdb
, traverse_fn
, (BRLOCK_FN_CAST())fn
);