got rid of USE_TDB_MMAP_FLAG as its not needed any more
[samba.git] / source3 / locking / locking.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Locking functions
5    Copyright (C) Andrew Tridgell 1992-2000
6    Copyright (C) Jeremy Allison 1992-2000
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22    Revision History:
23
24    12 aug 96: Erik.Devriendt@te6.siemens.be
25    added support for shared memory implementation of share mode locking
26
27    May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
28    locking to deal with multiple share modes per open file.
29
30    September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
31    support.
32
33    rewrtten completely to use new tdb code. Tridge, Dec '99
34
35    Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
36 */
37
38 #include "includes.h"
39 extern int DEBUGLEVEL;
40 uint16 global_smbpid;
41
42 /* the locking database handle */
43 static TDB_CONTEXT *tdb;
44
45 /****************************************************************************
46  Debugging aid :-).
47 ****************************************************************************/
48
49 static const char *lock_type_name(enum brl_type lock_type)
50 {
51         return (lock_type == READ_LOCK) ? "READ" : "WRITE";
52 }
53
54 /****************************************************************************
55  Utility function called to see if a file region is locked.
56  If check_self is True, then checks on our own fd with the same locking context
57  are still made. If check_self is False, then checks are not made on our own fd
58  with the same locking context are not made.
59 ****************************************************************************/
60
61 BOOL is_locked(files_struct *fsp,connection_struct *conn,
62                SMB_BIG_UINT count,SMB_BIG_UINT offset, 
63                enum brl_type lock_type, BOOL check_self)
64 {
65         int snum = SNUM(conn);
66         BOOL ret;
67         
68         if (count == 0)
69                 return(False);
70
71         if (!lp_locking(snum) || !lp_strict_locking(snum))
72                 return(False);
73
74         ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum,
75                              global_smbpid, sys_getpid(), conn->cnum, 
76                              offset, count, lock_type, check_self);
77
78         DEBUG(10,("is_locked: brl start=%.0f len=%.0f %s for file %s\n",
79                         (double)offset, (double)count, ret ? "locked" : "unlocked",
80                         fsp->fsp_name ));
81
82         /*
83          * There is no lock held by an SMB daemon, check to
84          * see if there is a POSIX lock from a UNIX or NFS process.
85          */
86
87         if(!ret && lp_posix_locking(snum)) {
88                 ret = is_posix_locked(fsp, offset, count, lock_type);
89
90                 DEBUG(10,("is_locked: posix start=%.0f len=%.0f %s for file %s\n",
91                                 (double)offset, (double)count, ret ? "locked" : "unlocked",
92                                 fsp->fsp_name ));
93         }
94
95         return ret;
96 }
97
98 /****************************************************************************
99  Utility function called by locking requests.
100 ****************************************************************************/
101
102 NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
103                  SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type)
104 {
105         NTSTATUS status;
106
107         if (!lp_locking(SNUM(conn)))
108                 return NT_STATUS_OK;
109
110         /* NOTE! 0 byte long ranges ARE allowed and should be stored  */
111
112
113         DEBUG(10,("do_lock: lock type %s start=%.0f len=%.0f requested for file %s\n",
114                   lock_type_name(lock_type), (double)offset, (double)count, fsp->fsp_name ));
115
116         if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) {
117                 status = brl_lock(fsp->dev, fsp->inode, fsp->fnum,
118                                   lock_pid, sys_getpid(), conn->cnum, 
119                                   offset, count, 
120                                   lock_type);
121
122                 if (NT_STATUS_IS_OK(status) && lp_posix_locking(SNUM(conn))) {
123
124                         /*
125                          * Try and get a POSIX lock on this range.
126                          * Note that this is ok if it is a read lock
127                          * overlapping on a different fd. JRA.
128                          */
129
130                         if (!set_posix_lock(fsp, offset, count, lock_type)) {
131                                 status = NT_STATUS_LOCK_NOT_GRANTED;
132                                 /*
133                                  * We failed to map - we must now remove the brl
134                                  * lock entry.
135                                  */
136                                 (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
137                                                                 lock_pid, sys_getpid(), conn->cnum, 
138                                                                 offset, count);
139                         }
140                 }
141         }
142
143         return status;
144 }
145
146 /****************************************************************************
147  Utility function called by unlocking requests.
148 ****************************************************************************/
149
150 NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
151                    SMB_BIG_UINT count,SMB_BIG_UINT offset)
152 {
153         BOOL ok = False;
154         
155         if (!lp_locking(SNUM(conn)))
156                 return NT_STATUS_OK;
157         
158         if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) {
159                 return NT_STATUS_INVALID_HANDLE;
160         }
161         
162         DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
163                   (double)offset, (double)count, fsp->fsp_name ));
164
165         /*
166          * Remove the existing lock record from the tdb lockdb
167          * before looking at POSIX locks. If this record doesn't
168          * match then don't bother looking to remove POSIX locks.
169          */
170
171         ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
172                         lock_pid, sys_getpid(), conn->cnum, offset, count);
173    
174         if (!ok) {
175                 DEBUG(10,("do_unlock: returning ERRlock.\n" ));
176                 return NT_STATUS_LOCK_NOT_GRANTED;
177         }
178
179         if (!lp_posix_locking(SNUM(conn)))
180                 return NT_STATUS_OK;
181
182         (void)release_posix_lock(fsp, offset, count);
183
184         return NT_STATUS_OK;
185 }
186
187 /****************************************************************************
188  Remove any locks on this fd. Called from file_close().
189 ****************************************************************************/
190
191 void locking_close_file(files_struct *fsp)
192 {
193         pid_t pid = sys_getpid();
194
195         if (!lp_locking(SNUM(fsp->conn)))
196                 return;
197
198         /*
199          * Just release all the brl locks, no need to release individually.
200          */
201
202         brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
203
204         if(lp_posix_locking(SNUM(fsp->conn))) {
205
206                 /* 
207                  * Release all the POSIX locks.
208                  */
209                 posix_locking_close_file(fsp);
210
211         }
212 }
213
214 /****************************************************************************
215  Delete a record if it is for a dead process, if check_self is true, then
216  delete any records belonging to this pid also (there shouldn't be any).
217  This function is only called on locking startup and shutdown.
218 ****************************************************************************/
219
220 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
221 {
222         struct locking_data *data;
223         share_mode_entry *shares;
224         int i, del_count=0;
225         pid_t mypid = sys_getpid();
226         BOOL check_self = *(BOOL *)state;
227         int ret = 0;
228
229         tdb_chainlock(tdb, kbuf);
230
231         data = (struct locking_data *)dbuf.dptr;
232         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
233
234         for (i=0;i<data->num_share_mode_entries;) {
235
236                 if (check_self && (shares[i].pid == mypid)) {
237                         DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
238                                         (unsigned int)shares[i].pid ));
239                 } else if (!process_exists(shares[i].pid)) {
240                         DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Entry for pid %u and it no longer exists !\n",
241                                         (unsigned int)shares[i].pid ));
242                 } else {
243                         /* Process exists, leave this record alone. */
244                         i++;
245                         continue;
246                 }
247
248                 data->num_share_mode_entries--;
249                 memmove(&shares[i], &shares[i+1],
250                 dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
251                 del_count++;
252
253         }
254
255         /* the record has shrunk a bit */
256         dbuf.dsize -= del_count * sizeof(*shares);
257
258         /* store it back in the database */
259         if (data->num_share_mode_entries == 0) {
260                 if (tdb_delete(ttdb, kbuf) == -1)
261                         ret = -1;
262         } else {
263                 if (tdb_store(ttdb, kbuf, dbuf, TDB_REPLACE) == -1)
264                         ret = -1;
265         }
266
267         tdb_chainunlock(tdb, kbuf);
268         return ret;
269 }
270
271 /****************************************************************************
272  Initialise the locking functions.
273 ****************************************************************************/
274
275 static int open_read_only;
276
277 BOOL locking_init(int read_only)
278 {
279         BOOL check_self = False;
280
281         brl_init(read_only);
282
283         if (tdb)
284                 return True;
285
286         tdb = tdb_open_log(lock_path("locking.tdb"), 
287                        0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST), 
288                        read_only?O_RDONLY:O_RDWR|O_CREAT,
289                        0644);
290
291         if (!tdb) {
292                 DEBUG(0,("ERROR: Failed to initialise locking database\n"));
293                 return False;
294         }
295         
296         if (!posix_locking_init(read_only))
297                 return False;
298
299         /* delete any dead locks */
300         if (!read_only)
301                 tdb_traverse(tdb, delete_fn, &check_self);
302
303         open_read_only = read_only;
304
305         return True;
306 }
307
308 /*******************************************************************
309  Deinitialize the share_mode management.
310 ******************************************************************/
311
312 BOOL locking_end(void)
313 {
314         BOOL check_self = True;
315
316         brl_shutdown(open_read_only);
317         if (tdb) {
318
319                 /* delete any dead locks */
320
321                 if (!open_read_only)
322                         tdb_traverse(tdb, delete_fn, &check_self);
323
324                 if (tdb_close(tdb) != 0)
325                         return False;
326         }
327
328         return True;
329 }
330
331 /*******************************************************************
332  Form a static locking key for a dev/inode pair.
333 ******************************************************************/
334
335 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
336 {
337         static struct locking_key key;
338         TDB_DATA kbuf;
339
340         memset(&key, '\0', sizeof(key));
341         key.dev = dev;
342         key.inode = inode;
343         kbuf.dptr = (char *)&key;
344         kbuf.dsize = sizeof(key);
345         return kbuf;
346 }
347
348 static TDB_DATA locking_key_fsp(files_struct *fsp)
349 {
350         return locking_key(fsp->dev, fsp->inode);
351 }
352
353 #ifndef LOCK_SHARE_ENTRY_SPIN_COUNT
354 #define LOCK_SHARE_ENTRY_SPIN_COUNT 100
355 #endif
356
357 /*******************************************************************
358  Lock a hash bucket entry.
359 ******************************************************************/
360
361 BOOL lock_share_entry(connection_struct *conn,
362                       SMB_DEV_T dev, SMB_INO_T inode)
363 {
364 #if 1 /* JRATEST */
365         int count = 0;
366         for (count = 0; count < LOCK_SHARE_ENTRY_SPIN_COUNT; count++)
367                 if (tdb_chainlock(tdb, locking_key(dev, inode)) == 0)
368                         return True;
369                 else
370                         DEBUG(0,("lock_share_entry: locking (%d) for dev = %x, inode = %.0f failed with error %s\n",
371                                 count, (unsigned int)dev, (double)inode, strerror(errno) ));
372         return False;
373 #else
374         return tdb_chainlock(tdb, locking_key(dev, inode)) == 0;
375 #endif
376 }
377
378 /*******************************************************************
379  Unlock a hash bucket entry.
380 ******************************************************************/
381
382 void unlock_share_entry(connection_struct *conn,
383                         SMB_DEV_T dev, SMB_INO_T inode)
384 {
385         tdb_chainunlock(tdb, locking_key(dev, inode));
386 }
387
388 /*******************************************************************
389  Lock a hash bucket entry. use a fsp for convenience
390 ******************************************************************/
391
392 BOOL lock_share_entry_fsp(files_struct *fsp)
393 {
394 #if 1 /* JRATEST */
395         int count = 0;
396         for (count = 0; count < LOCK_SHARE_ENTRY_SPIN_COUNT; count++)
397                 if (tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0)
398                         return True;
399                 else
400                         DEBUG(0,("lock_share_entry_fsp: locking (%d) for dev = %x, inode = %.0f failed with error %s\n",
401                                 count, (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno) ));
402         return False;
403 #else
404         return tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0;
405 #endif
406 }
407
408 /*******************************************************************
409  Unlock a hash bucket entry.
410 ******************************************************************/
411
412 void unlock_share_entry_fsp(files_struct *fsp)
413 {
414         tdb_chainunlock(tdb, locking_key(fsp->dev, fsp->inode));
415 }
416
417 /*******************************************************************
418  Get all share mode entries for a dev/inode pair.
419 ********************************************************************/
420
421 int get_share_modes(connection_struct *conn, 
422                     SMB_DEV_T dev, SMB_INO_T inode, 
423                     share_mode_entry **shares)
424 {
425         TDB_DATA dbuf;
426         struct locking_data *data;
427         int ret;
428
429         *shares = NULL;
430
431         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
432         if (!dbuf.dptr)
433                 return 0;
434
435         data = (struct locking_data *)dbuf.dptr;
436         ret = data->num_share_mode_entries;
437         if(ret)
438                 *shares = (share_mode_entry *)memdup(dbuf.dptr + sizeof(*data), ret * sizeof(**shares));
439         free(dbuf.dptr);
440
441         if (! *shares)
442                 return 0;
443
444         return ret;
445 }
446
447 /*******************************************************************
448  Fill a share mode entry.
449 ********************************************************************/
450
451 static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_type)
452 {
453         share_mode_entry *e = (share_mode_entry *)p;
454         memset(e, '\0', sizeof(share_mode_entry));
455         e->pid = sys_getpid();
456         e->share_mode = fsp->share_mode;
457         e->op_port = port;
458         e->op_type = op_type;
459         memcpy((char *)&e->time, (char *)&fsp->open_time, sizeof(struct timeval));
460 }
461
462 /*******************************************************************
463  Check if two share mode entries are identical, ignoring oplock 
464  and port info. 
465 ********************************************************************/
466
467 BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2)
468 {
469         return (e1->pid == e2->pid &&
470                 (e1->share_mode & ~DELETE_ON_CLOSE_FLAG) == (e2->share_mode & ~DELETE_ON_CLOSE_FLAG) &&
471                 e1->time.tv_sec == e2->time.tv_sec &&
472                 e1->time.tv_usec == e2->time.tv_usec );
473 }
474
475 /*******************************************************************
476  Delete a specific share mode. Return the number
477  of entries left, and a memdup'ed copy of the entry deleted (if required).
478  Ignore if no entry deleted.
479 ********************************************************************/
480
481 ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
482                         share_mode_entry *entry, share_mode_entry **ppse)
483 {
484         TDB_DATA dbuf;
485         struct locking_data *data;
486         int i, del_count=0;
487         share_mode_entry *shares;
488         ssize_t count = 0;
489
490         if (ppse)
491                 *ppse = NULL;
492
493         /* read in the existing share modes */
494         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
495         if (!dbuf.dptr)
496                 return -1;
497
498         data = (struct locking_data *)dbuf.dptr;
499         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
500
501         /*
502          * Find any with this pid and delete it
503          * by overwriting with the rest of the data 
504          * from the record.
505          */
506
507         DEBUG(10,("del_share_mode: num_share_modes = %d\n", data->num_share_mode_entries ));
508
509         for (i=0;i<data->num_share_mode_entries;) {
510                 if (share_modes_identical(&shares[i], entry)) {
511                         if (ppse)
512                                 *ppse = memdup(&shares[i], sizeof(*shares));
513                         data->num_share_mode_entries--;
514                         memmove(&shares[i], &shares[i+1], 
515                                 dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
516                         del_count++;
517
518                         DEBUG(10,("del_share_mode: deleting entry %d\n", i ));
519
520                 } else {
521                         i++;
522                 }
523         }
524
525         if (del_count) {
526                 /* the record may have shrunk a bit */
527                 dbuf.dsize -= del_count * sizeof(*shares);
528
529                 count = (ssize_t)data->num_share_mode_entries;
530
531                 /* store it back in the database */
532                 if (data->num_share_mode_entries == 0) {
533                         if (tdb_delete(tdb, locking_key(dev, inode)) == -1)
534                                 count = -1;
535                 } else {
536                         if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1)
537                                 count = -1;
538                 }
539         }
540         free(dbuf.dptr);
541         return count;
542 }
543
544 /*******************************************************************
545  Del the share mode of a file for this process. Return the number
546  of entries left, and a memdup'ed copy of the entry deleted.
547 ********************************************************************/
548
549 ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse)
550 {
551         share_mode_entry entry;
552
553         /*
554          * Fake up a share_mode_entry for comparisons.
555          */
556
557         fill_share_mode((char *)&entry, fsp, 0, 0);
558         return del_share_entry(fsp->dev, fsp->inode, &entry, ppse);
559 }
560
561 /*******************************************************************
562  Set the share mode of a file. Return False on fail, True on success.
563 ********************************************************************/
564
565 BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type)
566 {
567         TDB_DATA dbuf;
568         struct locking_data *data;
569         char *p=NULL;
570         int size;
571         BOOL ret = True;
572                 
573         /* read in the existing share modes if any */
574         dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
575         if (!dbuf.dptr) {
576                 /* we'll need to create a new record */
577                 pstring fname;
578
579                 pstrcpy(fname, fsp->conn->connectpath);
580                 pstrcat(fname, "/");
581                 pstrcat(fname, fsp->fsp_name);
582
583                 size = sizeof(*data) + sizeof(share_mode_entry) + strlen(fname) + 1;
584                 p = (char *)malloc(size);
585                 if (!p)
586                         return False;
587                 data = (struct locking_data *)p;
588                 data->num_share_mode_entries = 1;
589                 pstrcpy(p + sizeof(*data) + sizeof(share_mode_entry), fname);
590                 fill_share_mode(p + sizeof(*data), fsp, port, op_type);
591                 dbuf.dptr = p;
592                 dbuf.dsize = size;
593                 if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1)
594                         ret = False;
595                 free(p);
596                 return ret;
597         }
598
599         /* we're adding to an existing entry - this is a bit fiddly */
600         data = (struct locking_data *)dbuf.dptr;
601
602         data->num_share_mode_entries++;
603         size = dbuf.dsize + sizeof(share_mode_entry);
604         p = malloc(size);
605         if (!p)
606                 return False;
607         memcpy(p, dbuf.dptr, sizeof(*data));
608         fill_share_mode(p + sizeof(*data), fsp, port, op_type);
609         memcpy(p + sizeof(*data) + sizeof(share_mode_entry), dbuf.dptr + sizeof(*data),
610                dbuf.dsize - sizeof(*data));
611         free(dbuf.dptr);
612         dbuf.dptr = p;
613         dbuf.dsize = size;
614         if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1)
615                 ret = False;
616         free(p);
617         return ret;
618 }
619
620 /*******************************************************************
621  A generic in-place modification call for share mode entries.
622 ********************************************************************/
623
624 static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry,
625                            void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
626                            void *param)
627 {
628         TDB_DATA dbuf;
629         struct locking_data *data;
630         int i;
631         share_mode_entry *shares;
632         BOOL need_store=False;
633
634         /* read in the existing share modes */
635         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
636         if (!dbuf.dptr)
637                 return False;
638
639         data = (struct locking_data *)dbuf.dptr;
640         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
641
642         /* find any with our pid and call the supplied function */
643         for (i=0;i<data->num_share_mode_entries;i++) {
644                 if (share_modes_identical(entry, &shares[i])) {
645                         mod_fn(&shares[i], dev, inode, param);
646                         need_store=True;
647                 }
648         }
649
650         /* if the mod fn was called then store it back */
651         if (need_store) {
652                 if (data->num_share_mode_entries == 0) {
653                         if (tdb_delete(tdb, locking_key(dev, inode)) == -1)
654                                 need_store = False;
655                 } else {
656                         if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1)
657                                 need_store = False;
658                 }
659         }
660
661         free(dbuf.dptr);
662         return need_store;
663 }
664
665 /*******************************************************************
666  Static function that actually does the work for the generic function
667  below.
668 ********************************************************************/
669
670 static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
671                                    void *param)
672 {
673         DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
674                   (unsigned int)dev, (double)inode ));
675         /* Delete the oplock info. */
676         entry->op_port = 0;
677         entry->op_type = NO_OPLOCK;
678 }
679
680 /*******************************************************************
681  Remove an oplock port and mode entry from a share mode.
682 ********************************************************************/
683
684 BOOL remove_share_oplock(files_struct *fsp)
685 {
686         share_mode_entry entry;
687         /*
688          * Fake up an entry for comparisons...
689          */
690         fill_share_mode((char *)&entry, fsp, 0, 0);
691         return mod_share_mode(fsp->dev, fsp->inode, &entry, remove_share_oplock_fn, NULL);
692 }
693
694 /*******************************************************************
695  Static function that actually does the work for the generic function
696  below.
697 ********************************************************************/
698
699 static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
700                                    void *param)
701 {
702         DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
703                   (unsigned int)dev, (double)inode ));
704         entry->op_type = LEVEL_II_OPLOCK;
705 }
706
707 /*******************************************************************
708  Downgrade a oplock type from exclusive to level II.
709 ********************************************************************/
710
711 BOOL downgrade_share_oplock(files_struct *fsp)
712 {
713         share_mode_entry entry;
714         /*
715          * Fake up an entry for comparisons...
716          */
717         fill_share_mode((char *)&entry, fsp, 0, 0);
718         return mod_share_mode(fsp->dev, fsp->inode, &entry, downgrade_share_oplock_fn, NULL);
719 }
720
721 /*******************************************************************
722  Get/Set the delete on close flag in a set of share modes.
723  Return False on fail, True on success.
724 ********************************************************************/
725
726 BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close)
727 {
728         TDB_DATA dbuf;
729         struct locking_data *data;
730         int i;
731         share_mode_entry *shares;
732
733         /* read in the existing share modes */
734         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
735         if (!dbuf.dptr)
736                 return False;
737
738         data = (struct locking_data *)dbuf.dptr;
739         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
740
741         /* Set/Unset the delete on close element. */
742         for (i=0;i<data->num_share_mode_entries;i++,shares++) {
743                 shares->share_mode = (delete_on_close ?
744                             (shares->share_mode | DELETE_ON_CLOSE_FLAG) :
745                             (shares->share_mode & ~DELETE_ON_CLOSE_FLAG) );
746         }
747
748         /* store it back */
749         if (data->num_share_mode_entries) {
750                 if (tdb_store(tdb, locking_key(dev,inode), dbuf, TDB_REPLACE)==-1) {
751                         free(dbuf.dptr);
752                         return False;
753                 }
754         }
755
756         free(dbuf.dptr);
757         return True;
758 }
759
760 /****************************************************************************
761  Traverse the whole database with this function, calling traverse_callback
762  on each share mode
763 ****************************************************************************/
764
765 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
766                        void* state)
767 {
768         struct locking_data *data;
769         share_mode_entry *shares;
770         char *name;
771         int i;
772
773         SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state;
774
775         data = (struct locking_data *)dbuf.dptr;
776         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
777         name = dbuf.dptr + sizeof(*data) + data->num_share_mode_entries*sizeof(*shares);
778
779         for (i=0;i<data->num_share_mode_entries;i++) {
780                 traverse_callback(&shares[i], name);
781         }
782         return 0;
783 }
784
785 /*******************************************************************
786  Call the specified function on each entry under management by the
787  share mode system.
788 ********************************************************************/
789
790 int share_mode_forall(SHAREMODE_FN(fn))
791 {
792         if (!tdb)
793                 return 0;
794         return tdb_traverse(tdb, traverse_fn, (void*)fn);
795 }