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