converted another bunch of stuff to NTSTATUS
[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         BOOL ok = False;
106
107         if (!lp_locking(SNUM(conn)))
108                 return NT_STATUS(0);
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                 ok = brl_lock(fsp->dev, fsp->inode, fsp->fnum,
118                               lock_pid, sys_getpid(), conn->cnum, 
119                               offset, count, 
120                               lock_type);
121
122                 if (ok && 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                         ok = set_posix_lock(fsp, offset, count, lock_type);
131
132                         if (!ok) {
133                                 /*
134                                  * We failed to map - we must now remove the brl
135                                  * lock entry.
136                                  */
137                                 (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
138                                                                 lock_pid, sys_getpid(), conn->cnum, 
139                                                                 offset, count);
140                         }
141                 }
142         }
143
144         if (!ok) return NT_STATUS_FILE_LOCK_CONFLICT;
145
146         return NT_STATUS_OK; /* Got lock */
147 }
148
149 /****************************************************************************
150  Utility function called by unlocking requests.
151 ****************************************************************************/
152
153 NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
154                    SMB_BIG_UINT count,SMB_BIG_UINT offset)
155 {
156         BOOL ok = False;
157         
158         if (!lp_locking(SNUM(conn)))
159                 return NT_STATUS(0);
160         
161         if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) {
162                 return NT_STATUS(NT_STATUS_INVALID_HANDLE);
163         }
164         
165         DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
166                   (double)offset, (double)count, fsp->fsp_name ));
167
168         /*
169          * Remove the existing lock record from the tdb lockdb
170          * before looking at POSIX locks. If this record doesn't
171          * match then don't bother looking to remove POSIX locks.
172          */
173
174         ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
175                         lock_pid, sys_getpid(), conn->cnum, offset, count);
176    
177         if (!ok) {
178                 DEBUG(10,("do_unlock: returning ERRlock.\n" ));
179                 return NT_STATUS(NT_STATUS_LOCK_NOT_GRANTED);
180         }
181
182         if (!lp_posix_locking(SNUM(conn)))
183                 return NT_STATUS(0);
184
185         (void)release_posix_lock(fsp, offset, count);
186
187         return NT_STATUS(0);
188 }
189
190 /****************************************************************************
191  Remove any locks on this fd. Called from file_close().
192 ****************************************************************************/
193
194 void locking_close_file(files_struct *fsp)
195 {
196         pid_t pid = sys_getpid();
197
198         if (!lp_locking(SNUM(fsp->conn)))
199                 return;
200
201         /*
202          * Just release all the brl locks, no need to release individually.
203          */
204
205         brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
206
207         if(lp_posix_locking(SNUM(fsp->conn))) {
208
209                 /* 
210                  * Release all the POSIX locks.
211                  */
212                 posix_locking_close_file(fsp);
213
214         }
215 }
216
217 /****************************************************************************
218  Delete a record if it is for a dead process, if check_self is true, then
219  delete any records belonging to this pid also (there shouldn't be any).
220  This function is only called on locking startup and shutdown.
221 ****************************************************************************/
222
223 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
224 {
225         struct locking_data *data;
226         share_mode_entry *shares;
227         int i, del_count=0;
228         pid_t mypid = sys_getpid();
229         BOOL check_self = *(BOOL *)state;
230         int ret = 0;
231
232         tdb_chainlock(tdb, kbuf);
233
234         data = (struct locking_data *)dbuf.dptr;
235         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
236
237         for (i=0;i<data->num_share_mode_entries;) {
238
239                 if (check_self && (shares[i].pid == mypid)) {
240                         DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
241                                         (unsigned int)shares[i].pid ));
242                 } else if (!process_exists(shares[i].pid)) {
243                         DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Entry for pid %u and it no longer exists !\n",
244                                         (unsigned int)shares[i].pid ));
245                 } else {
246                         /* Process exists, leave this record alone. */
247                         i++;
248                         continue;
249                 }
250
251                 data->num_share_mode_entries--;
252                 memmove(&shares[i], &shares[i+1],
253                 dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
254                 del_count++;
255
256         }
257
258         /* the record has shrunk a bit */
259         dbuf.dsize -= del_count * sizeof(*shares);
260
261         /* store it back in the database */
262         if (data->num_share_mode_entries == 0) {
263                 if (tdb_delete(ttdb, kbuf) == -1)
264                         ret = -1;
265         } else {
266                 if (tdb_store(ttdb, kbuf, dbuf, TDB_REPLACE) == -1)
267                         ret = -1;
268         }
269
270         tdb_chainunlock(tdb, kbuf);
271         return ret;
272 }
273
274 /****************************************************************************
275  Initialise the locking functions.
276 ****************************************************************************/
277
278 static int open_read_only;
279
280 BOOL locking_init(int read_only)
281 {
282         BOOL check_self = False;
283
284         brl_init(read_only);
285
286         if (tdb)
287                 return True;
288
289         tdb = tdb_open_log(lock_path("locking.tdb"), 
290                        0, USE_TDB_MMAP_FLAG|(read_only?0x0:TDB_CLEAR_IF_FIRST), 
291                        read_only?O_RDONLY:O_RDWR|O_CREAT,
292                        0644);
293
294         if (!tdb) {
295                 DEBUG(0,("ERROR: Failed to initialise locking database\n"));
296                 return False;
297         }
298         
299         if (!posix_locking_init(read_only))
300                 return False;
301
302         /* delete any dead locks */
303         if (!read_only)
304                 tdb_traverse(tdb, delete_fn, &check_self);
305
306         open_read_only = read_only;
307
308         return True;
309 }
310
311 /*******************************************************************
312  Deinitialize the share_mode management.
313 ******************************************************************/
314
315 BOOL locking_end(void)
316 {
317         BOOL check_self = True;
318
319         brl_shutdown(open_read_only);
320         if (tdb) {
321
322                 /* delete any dead locks */
323
324                 if (!open_read_only)
325                         tdb_traverse(tdb, delete_fn, &check_self);
326
327                 if (tdb_close(tdb) != 0)
328                         return False;
329         }
330
331         return True;
332 }
333
334 /*******************************************************************
335  Form a static locking key for a dev/inode pair.
336 ******************************************************************/
337
338 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
339 {
340         static struct locking_key key;
341         TDB_DATA kbuf;
342
343         memset(&key, '\0', sizeof(key));
344         key.dev = dev;
345         key.inode = inode;
346         kbuf.dptr = (char *)&key;
347         kbuf.dsize = sizeof(key);
348         return kbuf;
349 }
350
351 static TDB_DATA locking_key_fsp(files_struct *fsp)
352 {
353         return locking_key(fsp->dev, fsp->inode);
354 }
355
356 #ifndef LOCK_SHARE_ENTRY_SPIN_COUNT
357 #define LOCK_SHARE_ENTRY_SPIN_COUNT 100
358 #endif
359
360 /*******************************************************************
361  Lock a hash bucket entry.
362 ******************************************************************/
363
364 BOOL lock_share_entry(connection_struct *conn,
365                       SMB_DEV_T dev, SMB_INO_T inode)
366 {
367 #if 1 /* JRATEST */
368         int count = 0;
369         for (count = 0; count < LOCK_SHARE_ENTRY_SPIN_COUNT; count++)
370                 if (tdb_chainlock(tdb, locking_key(dev, inode)) == 0)
371                         return True;
372                 else
373                         DEBUG(0,("lock_share_entry: locking (%d) for dev = %x, inode = %.0f failed with error %s\n",
374                                 count, (unsigned int)dev, (double)inode, strerror(errno) ));
375         return False;
376 #else
377         return tdb_chainlock(tdb, locking_key(dev, inode)) == 0;
378 #endif
379 }
380
381 /*******************************************************************
382  Unlock a hash bucket entry.
383 ******************************************************************/
384
385 void unlock_share_entry(connection_struct *conn,
386                         SMB_DEV_T dev, SMB_INO_T inode)
387 {
388         tdb_chainunlock(tdb, locking_key(dev, inode));
389 }
390
391 /*******************************************************************
392  Lock a hash bucket entry. use a fsp for convenience
393 ******************************************************************/
394
395 BOOL lock_share_entry_fsp(files_struct *fsp)
396 {
397 #if 1 /* JRATEST */
398         int count = 0;
399         for (count = 0; count < LOCK_SHARE_ENTRY_SPIN_COUNT; count++)
400                 if (tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0)
401                         return True;
402                 else
403                         DEBUG(0,("lock_share_entry_fsp: locking (%d) for dev = %x, inode = %.0f failed with error %s\n",
404                                 count, (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno) ));
405         return False;
406 #else
407         return tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0;
408 #endif
409 }
410
411 /*******************************************************************
412  Unlock a hash bucket entry.
413 ******************************************************************/
414
415 void unlock_share_entry_fsp(files_struct *fsp)
416 {
417         tdb_chainunlock(tdb, locking_key(fsp->dev, fsp->inode));
418 }
419
420 /*******************************************************************
421  Get all share mode entries for a dev/inode pair.
422 ********************************************************************/
423
424 int get_share_modes(connection_struct *conn, 
425                     SMB_DEV_T dev, SMB_INO_T inode, 
426                     share_mode_entry **shares)
427 {
428         TDB_DATA dbuf;
429         struct locking_data *data;
430         int ret;
431
432         *shares = NULL;
433
434         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
435         if (!dbuf.dptr)
436                 return 0;
437
438         data = (struct locking_data *)dbuf.dptr;
439         ret = data->num_share_mode_entries;
440         if(ret)
441                 *shares = (share_mode_entry *)memdup(dbuf.dptr + sizeof(*data), ret * sizeof(**shares));
442         free(dbuf.dptr);
443
444         if (! *shares)
445                 return 0;
446
447         return ret;
448 }
449
450 /*******************************************************************
451  Fill a share mode entry.
452 ********************************************************************/
453
454 static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_type)
455 {
456         share_mode_entry *e = (share_mode_entry *)p;
457         memset(e, '\0', sizeof(share_mode_entry));
458         e->pid = sys_getpid();
459         e->share_mode = fsp->share_mode;
460         e->op_port = port;
461         e->op_type = op_type;
462         memcpy((char *)&e->time, (char *)&fsp->open_time, sizeof(struct timeval));
463 }
464
465 /*******************************************************************
466  Check if two share mode entries are identical, ignoring oplock 
467  and port info. 
468 ********************************************************************/
469
470 BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2)
471 {
472         return (e1->pid == e2->pid &&
473           e1->share_mode == e2->share_mode &&
474           e1->time.tv_sec == e2->time.tv_sec &&
475           e1->time.tv_usec == e2->time.tv_usec );
476 }
477
478 /*******************************************************************
479  Delete a specific share mode. Return the number
480  of entries left, and a memdup'ed copy of the entry deleted (if required).
481  Ignore if no entry deleted.
482 ********************************************************************/
483
484 ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
485                         share_mode_entry *entry, share_mode_entry **ppse)
486 {
487         TDB_DATA dbuf;
488         struct locking_data *data;
489         int i, del_count=0;
490         share_mode_entry *shares;
491         ssize_t count = 0;
492
493         if (ppse)
494                 *ppse = NULL;
495
496         /* read in the existing share modes */
497         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
498         if (!dbuf.dptr)
499                 return -1;
500
501         data = (struct locking_data *)dbuf.dptr;
502         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
503
504         /*
505          * Find any with this pid and delete it
506          * by overwriting with the rest of the data 
507          * from the record.
508          */
509
510         DEBUG(10,("del_share_mode: num_share_modes = %d\n", data->num_share_mode_entries ));
511
512         for (i=0;i<data->num_share_mode_entries;) {
513                 if (share_modes_identical(&shares[i], entry)) {
514                         if (ppse)
515                                 *ppse = memdup(&shares[i], sizeof(*shares));
516                         data->num_share_mode_entries--;
517                         memmove(&shares[i], &shares[i+1], 
518                                 dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
519                         del_count++;
520
521                         DEBUG(10,("del_share_mode: deleting entry %d\n", i ));
522
523                 } else {
524                         i++;
525                 }
526         }
527
528         if (del_count) {
529                 /* the record may have shrunk a bit */
530                 dbuf.dsize -= del_count * sizeof(*shares);
531
532                 count = (ssize_t)data->num_share_mode_entries;
533
534                 /* store it back in the database */
535                 if (data->num_share_mode_entries == 0) {
536                         if (tdb_delete(tdb, locking_key(dev, inode)) == -1)
537                                 count = -1;
538                 } else {
539                         if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1)
540                                 count = -1;
541                 }
542         }
543         free(dbuf.dptr);
544         return count;
545 }
546
547 /*******************************************************************
548  Del the share mode of a file for this process. Return the number
549  of entries left, and a memdup'ed copy of the entry deleted.
550 ********************************************************************/
551
552 ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse)
553 {
554         share_mode_entry entry;
555
556         /*
557          * Fake up a share_mode_entry for comparisons.
558          */
559
560         fill_share_mode((char *)&entry, fsp, 0, 0);
561         return del_share_entry(fsp->dev, fsp->inode, &entry, ppse);
562 }
563
564 /*******************************************************************
565  Set the share mode of a file. Return False on fail, True on success.
566 ********************************************************************/
567
568 BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type)
569 {
570         TDB_DATA dbuf;
571         struct locking_data *data;
572         char *p=NULL;
573         int size;
574         BOOL ret = True;
575                 
576         /* read in the existing share modes if any */
577         dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
578         if (!dbuf.dptr) {
579                 /* we'll need to create a new record */
580                 pstring fname;
581
582                 pstrcpy(fname, fsp->conn->connectpath);
583                 pstrcat(fname, "/");
584                 pstrcat(fname, fsp->fsp_name);
585
586                 size = sizeof(*data) + sizeof(share_mode_entry) + strlen(fname) + 1;
587                 p = (char *)malloc(size);
588                 if (!p)
589                         return False;
590                 data = (struct locking_data *)p;
591                 data->num_share_mode_entries = 1;
592                 pstrcpy(p + sizeof(*data) + sizeof(share_mode_entry), fname);
593                 fill_share_mode(p + sizeof(*data), fsp, port, op_type);
594                 dbuf.dptr = p;
595                 dbuf.dsize = size;
596                 if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1)
597                         ret = False;
598                 free(p);
599                 return ret;
600         }
601
602         /* we're adding to an existing entry - this is a bit fiddly */
603         data = (struct locking_data *)dbuf.dptr;
604
605         data->num_share_mode_entries++;
606         size = dbuf.dsize + sizeof(share_mode_entry);
607         p = malloc(size);
608         if (!p)
609                 return False;
610         memcpy(p, dbuf.dptr, sizeof(*data));
611         fill_share_mode(p + sizeof(*data), fsp, port, op_type);
612         memcpy(p + sizeof(*data) + sizeof(share_mode_entry), dbuf.dptr + sizeof(*data),
613                dbuf.dsize - sizeof(*data));
614         free(dbuf.dptr);
615         dbuf.dptr = p;
616         dbuf.dsize = size;
617         if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1)
618                 ret = False;
619         free(p);
620         return ret;
621 }
622
623 /*******************************************************************
624  A generic in-place modification call for share mode entries.
625 ********************************************************************/
626
627 static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry,
628                            void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
629                            void *param)
630 {
631         TDB_DATA dbuf;
632         struct locking_data *data;
633         int i;
634         share_mode_entry *shares;
635         BOOL need_store=False;
636
637         /* read in the existing share modes */
638         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
639         if (!dbuf.dptr)
640                 return False;
641
642         data = (struct locking_data *)dbuf.dptr;
643         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
644
645         /* find any with our pid and call the supplied function */
646         for (i=0;i<data->num_share_mode_entries;i++) {
647                 if (share_modes_identical(entry, &shares[i])) {
648                         mod_fn(&shares[i], dev, inode, param);
649                         need_store=True;
650                 }
651         }
652
653         /* if the mod fn was called then store it back */
654         if (need_store) {
655                 if (data->num_share_mode_entries == 0) {
656                         if (tdb_delete(tdb, locking_key(dev, inode)) == -1)
657                                 need_store = False;
658                 } else {
659                         if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1)
660                                 need_store = False;
661                 }
662         }
663
664         free(dbuf.dptr);
665         return need_store;
666 }
667
668 /*******************************************************************
669  Static function that actually does the work for the generic function
670  below.
671 ********************************************************************/
672
673 static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
674                                    void *param)
675 {
676         DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
677                   (unsigned int)dev, (double)inode ));
678         /* Delete the oplock info. */
679         entry->op_port = 0;
680         entry->op_type = NO_OPLOCK;
681 }
682
683 /*******************************************************************
684  Remove an oplock port and mode entry from a share mode.
685 ********************************************************************/
686
687 BOOL remove_share_oplock(files_struct *fsp)
688 {
689         share_mode_entry entry;
690         /*
691          * Fake up an entry for comparisons...
692          */
693         fill_share_mode((char *)&entry, fsp, 0, 0);
694         return mod_share_mode(fsp->dev, fsp->inode, &entry, remove_share_oplock_fn, NULL);
695 }
696
697 /*******************************************************************
698  Static function that actually does the work for the generic function
699  below.
700 ********************************************************************/
701
702 static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
703                                    void *param)
704 {
705         DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
706                   (unsigned int)dev, (double)inode ));
707         entry->op_type = LEVEL_II_OPLOCK;
708 }
709
710 /*******************************************************************
711  Downgrade a oplock type from exclusive to level II.
712 ********************************************************************/
713
714 BOOL downgrade_share_oplock(files_struct *fsp)
715 {
716         share_mode_entry entry;
717         /*
718          * Fake up an entry for comparisons...
719          */
720         fill_share_mode((char *)&entry, fsp, 0, 0);
721         return mod_share_mode(fsp->dev, fsp->inode, &entry, downgrade_share_oplock_fn, NULL);
722 }
723
724 /*******************************************************************
725  Get/Set the delete on close flag in a set of share modes.
726  Return False on fail, True on success.
727 ********************************************************************/
728
729 BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close)
730 {
731         TDB_DATA dbuf;
732         struct locking_data *data;
733         int i;
734         share_mode_entry *shares;
735
736         /* read in the existing share modes */
737         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
738         if (!dbuf.dptr)
739                 return False;
740
741         data = (struct locking_data *)dbuf.dptr;
742         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
743
744         /* Set/Unset the delete on close element. */
745         for (i=0;i<data->num_share_mode_entries;i++,shares++) {
746                 shares->share_mode = (delete_on_close ?
747                             (shares->share_mode | DELETE_ON_CLOSE_FLAG) :
748                             (shares->share_mode & ~DELETE_ON_CLOSE_FLAG) );
749         }
750
751         /* store it back */
752         if (data->num_share_mode_entries) {
753                 if (tdb_store(tdb, locking_key(dev,inode), dbuf, TDB_REPLACE)==-1) {
754                         free(dbuf.dptr);
755                         return False;
756                 }
757         }
758
759         free(dbuf.dptr);
760         return True;
761 }
762
763 /****************************************************************************
764  Traverse the whole database with this function, calling traverse_callback
765  on each share mode
766 ****************************************************************************/
767
768 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
769                        void* state)
770 {
771         struct locking_data *data;
772         share_mode_entry *shares;
773         char *name;
774         int i;
775
776         SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state;
777
778         data = (struct locking_data *)dbuf.dptr;
779         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
780         name = dbuf.dptr + sizeof(*data) + data->num_share_mode_entries*sizeof(*shares);
781
782         for (i=0;i<data->num_share_mode_entries;i++) {
783                 traverse_callback(&shares[i], name);
784         }
785         return 0;
786 }
787
788 /*******************************************************************
789  Call the specified function on each entry under management by the
790  share mode system.
791 ********************************************************************/
792
793 int share_mode_forall(SHAREMODE_FN(fn))
794 {
795         if (!tdb)
796                 return 0;
797         return tdb_traverse(tdb, traverse_fn, (void*)fn);
798 }