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