- removed all our old wildcard matching code and replaced it with a
[kamenim/samba-autobuild/.git] / source3 / locking / posix.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Locking functions
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    POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
24 */
25
26 #include "includes.h"
27 extern int DEBUGLEVEL;
28 extern int global_smbpid;
29
30 /*
31  * The POSIX locking database handle.
32  */
33
34 static TDB_CONTEXT *posix_lock_tdb;
35
36 /*
37  * The pending close database handle.
38  */
39
40 static TDB_CONTEXT *posix_pending_close_tdb;
41
42 /*
43  * The data in POSIX lock records is an unsorted linear array of these
44  * records.  It is unnecessary to store the count as tdb provides the
45  * size of the record.
46  */
47
48 struct posix_lock {
49         int fd;
50         SMB_OFF_T start;
51         SMB_OFF_T size;
52         int lock_type;
53 };
54
55 /*
56  * The data in POSIX pending close records is an unsorted linear array of int
57  * records.  It is unnecessary to store the count as tdb provides the
58  * size of the record.
59  */
60
61 /* The key used in both the POSIX databases. */
62
63 struct posix_lock_key {
64         SMB_DEV_T device;
65         SMB_INO_T inode;
66 }; 
67
68 /*******************************************************************
69  Form a static locking key for a dev/inode pair.
70 ******************************************************************/
71
72 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
73 {
74         static struct posix_lock_key key;
75         TDB_DATA kbuf;
76         key.device = dev;
77         key.inode = inode;
78         kbuf.dptr = (char *)&key;
79         kbuf.dsize = sizeof(key);
80         return kbuf;
81 }
82
83 /*******************************************************************
84  Convenience function to get a key from an fsp.
85 ******************************************************************/
86
87 static TDB_DATA locking_key_fsp(files_struct *fsp)
88 {
89         return locking_key(fsp->dev, fsp->inode);
90 }
91
92 /****************************************************************************
93  Add an fd to the pending close tdb.
94 ****************************************************************************/
95
96 static BOOL add_fd_to_close_entry(files_struct *fsp)
97 {
98         TDB_DATA kbuf = locking_key_fsp(fsp);
99         TDB_DATA dbuf;
100
101         dbuf.dptr = NULL;
102
103         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
104
105         dbuf.dptr = Realloc(dbuf.dptr, dbuf.dsize + sizeof(int));
106         if (!dbuf.dptr) {
107                 DEBUG(0,("add_fd_to_close_entry: Realloc fail !\n"));
108                 return False;
109         }
110         memcpy(dbuf.dptr + dbuf.dsize, &fsp->fd, sizeof(int));
111         dbuf.dsize += sizeof(int);
112
113         if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
114                 DEBUG(0,("add_fd_to_close_entry: tdb_store fail !\n"));
115         }
116
117         free(dbuf.dptr);
118         return True;
119 }
120
121 /****************************************************************************
122  Remove all fd entries for a specific dev/inode pair from the tdb.
123 ****************************************************************************/
124
125 static void delete_close_entries(files_struct *fsp)
126 {
127         TDB_DATA kbuf = locking_key_fsp(fsp);
128
129         if (tdb_delete(posix_pending_close_tdb, kbuf) == -1)
130                 DEBUG(0,("delete_close_entries: tdb_delete fail !\n"));
131 }
132
133 /****************************************************************************
134  Get the array of POSIX pending close records for an open fsp. Caller must
135  free. Returns number of entries.
136 ****************************************************************************/
137
138 static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries)
139 {
140         TDB_DATA kbuf = locking_key_fsp(fsp);
141         TDB_DATA dbuf;
142         size_t count = 0;
143
144         *entries = NULL;
145         dbuf.dptr = NULL;
146
147         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
148
149     if (!dbuf.dptr) {
150                 return 0;
151         }
152
153         *entries = (int *)dbuf.dptr;
154         count = (size_t)(dbuf.dsize / sizeof(int));
155
156         return count;
157 }
158
159 /****************************************************************************
160  Get the array of POSIX locks for an fsp. Caller must free. Returns
161  number of entries.
162 ****************************************************************************/
163
164 static size_t get_posix_lock_entries(files_struct *fsp, struct posix_lock **entries)
165 {
166         TDB_DATA kbuf = locking_key_fsp(fsp);
167         TDB_DATA dbuf;
168         size_t count = 0;
169
170         *entries = NULL;
171
172         dbuf.dptr = NULL;
173
174         dbuf = tdb_fetch(posix_lock_tdb, kbuf);
175
176     if (!dbuf.dptr) {
177                 return 0;
178         }
179
180         *entries = (struct posix_lock *)dbuf.dptr;
181         count = (size_t)(dbuf.dsize / sizeof(struct posix_lock));
182
183         return count;
184 }
185
186 /****************************************************************************
187  Deal with pending closes needed by POSIX locking support.
188 ****************************************************************************/
189
190 int fd_close_posix(struct connection_struct *conn, files_struct *fsp)
191 {
192         int saved_errno = 0;
193         int ret;
194         size_t count, i;
195         struct posix_lock *entries = NULL;
196         int *fd_array = NULL;
197
198         if (!lp_posix_locking(SNUM(conn))) {
199                 /*
200                  * No POSIX to worry about, just close.
201                  */
202                 ret = conn->vfs_ops.close(fsp->fd);
203                 fsp->fd = -1;
204                 return ret;
205         }
206
207         /*
208          * Get the number of outstanding POSIX locks on this dev/inode pair.
209          */
210
211         count = get_posix_lock_entries(fsp, &entries);
212         
213         if (count) {
214
215                 /*
216                  * There are outstanding locks on this dev/inode pair on other fds.
217                  * Add our fd to the pending close tdb and set fsp->fd to -1.
218                  */
219
220                 if (!add_fd_to_close_entry(fsp)) {
221                         free((char *)entries);
222                         return False;
223                 }
224
225                 free((char *)entries);
226                 fsp->fd = -1;
227                 return 0;
228         }
229
230         if(entries)
231                 free((char *)entries);
232
233         /*
234          * No outstanding POSIX locks. Get the pending close fd's
235          * from the tdb and close them all.
236          */
237
238         count = get_posix_pending_close_entries(fsp, &fd_array);
239
240         if (count) {
241                 DEBUG(10,("fd_close_posix: doing close on %u fd's.\n", (unsigned int)count ));
242
243                 for(i = 0; i < count; i++) {
244                         if (conn->vfs_ops.close(fd_array[i]) == -1) {
245                                 saved_errno = errno;
246                         }
247                 }
248
249                 if (fd_array)
250                         free((char *)fd_array);
251
252                 /*
253                  * Delete all fd's stored in the tdb
254                  * for this dev/inode pair.
255                  */
256
257                 delete_close_entries(fsp);
258         }
259
260         if (fd_array)
261                 free((char *)fd_array);
262
263         /*
264          * Finally close the fd associated with this fsp.
265          */
266
267         ret = conn->vfs_ops.close(fsp->fd);
268
269         if (saved_errno != 0) {
270         errno = saved_errno;
271                 ret = -1;
272     } 
273
274         fsp->fd = -1;
275
276         return ret;
277 }
278
279 /****************************************************************************
280  Debugging aid :-).
281 ****************************************************************************/
282
283 static const char *posix_lock_type_name(int lock_type)
284 {
285         return (lock_type == F_RDLCK) ? "READ" : "WRITE";
286 }
287
288 /****************************************************************************
289  Add an entry into the POSIX locking tdb.
290 ****************************************************************************/
291
292 static BOOL add_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size, int lock_type)
293 {
294         TDB_DATA kbuf = locking_key_fsp(fsp);
295         TDB_DATA dbuf;
296         struct posix_lock pl;
297
298         /*
299          * Now setup the new record.
300          */
301
302         pl.fd = fsp->fd;
303         pl.start = start;
304         pl.size = size;
305         pl.lock_type = lock_type;
306
307         dbuf.dptr = NULL;
308
309         dbuf = tdb_fetch(posix_lock_tdb, kbuf);
310
311         dbuf.dptr = Realloc(dbuf.dptr, dbuf.dsize + sizeof(pl));
312         if (!dbuf.dptr) {
313                 DEBUG(0,("add_posix_lock_entry: Realloc fail !\n"));
314                 goto fail;
315         }
316
317         memcpy(dbuf.dptr + dbuf.dsize, &pl, sizeof(pl));
318         dbuf.dsize += sizeof(pl);
319
320         if (tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
321                 DEBUG(0,("add_posix_lock: Failed to add lock entry on file %s\n", fsp->fsp_name));
322                 goto fail;
323         }
324
325     free(dbuf.dptr);
326
327         DEBUG(10,("add_posix_lock: File %s: type = %s: start=%.0f size=%.0f:dev=%.0f inode=%.0f\n",
328                         fsp->fsp_name, posix_lock_type_name(lock_type), (double)start, (double)size,
329                         (double)fsp->dev, (double)fsp->inode ));
330
331     return True;
332
333  fail:
334     if (dbuf.dptr)
335                 free(dbuf.dptr);
336     return False;
337 }
338
339 /****************************************************************************
340  Delete an entry from the POSIX locking tdb.
341 ****************************************************************************/
342
343 static BOOL delete_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size)
344 {
345         TDB_DATA kbuf = locking_key_fsp(fsp);
346         TDB_DATA dbuf;
347         struct posix_lock *locks;
348         size_t i, count;
349
350         dbuf.dptr = NULL;
351
352         dbuf = tdb_fetch(posix_lock_tdb, kbuf);
353
354         if (!dbuf.dptr) {
355                 DEBUG(10,("delete_posix_lock_entry: tdb_fetch failed !\n"));
356                 goto fail;
357         }
358
359         /* There are existing locks - find a match. */
360         locks = (struct posix_lock *)dbuf.dptr;
361         count = (size_t)(dbuf.dsize / sizeof(*locks));
362
363         for (i=0; i<count; i++) { 
364                 struct posix_lock *pl = &locks[i];
365
366                 if (pl->fd == fsp->fd &&
367                         pl->start == start &&
368                         pl->size == size) {
369                         /* Found it - delete it. */
370                         if (count == 1) {
371                                 tdb_delete(posix_lock_tdb, kbuf);
372                         } else {
373                                 if (i < count-1) {
374                                         memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i));
375                                 }
376                                 dbuf.dsize -= sizeof(*locks);
377                                 tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE);
378                         }
379
380                         free(dbuf.dptr);
381                         return True;
382                 }
383         }
384
385         /* We didn't find it. */
386
387  fail:
388     if (dbuf.dptr)
389                 free(dbuf.dptr);
390     return False;
391 }
392
393 /****************************************************************************
394  Utility function to map a lock type correctly depending on the open
395  mode of a file.
396 ****************************************************************************/
397
398 static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type)
399 {
400         if((lock_type == WRITE_LOCK) && !fsp->can_write) {
401                 /*
402                  * Many UNIX's cannot get a write lock on a file opened read-only.
403                  * Win32 locking semantics allow this.
404                  * Do the best we can and attempt a read-only lock.
405                  */
406                 DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n"));
407                 return F_RDLCK;
408         } else if((lock_type == READ_LOCK) && !fsp->can_read) {
409                 /*
410                  * Ditto for read locks on write only files.
411                  */
412                 DEBUG(10,("map_posix_lock_type: Changing read lock to write due to write-only file.\n"));
413                 return F_WRLCK;
414         }
415
416   /*
417    * This return should be the most normal, as we attempt
418    * to always open files read/write.
419    */
420
421   return (lock_type == READ_LOCK) ? F_RDLCK : F_WRLCK;
422 }
423
424 /****************************************************************************
425  Check to see if the given unsigned lock range is within the possible POSIX
426  range. Modifies the given args to be in range if possible, just returns
427  False if not.
428 ****************************************************************************/
429
430 static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
431                                                                 SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
432 {
433         SMB_OFF_T offset;
434         SMB_OFF_T count;
435
436 #if defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
437
438     SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4);
439     SMB_OFF_T mask = (mask2<<1);
440     SMB_OFF_T neg_mask = ~mask;
441
442         /*
443          * In this case SMB_OFF_T is 64 bits,
444          * and the underlying system can handle 64 bit signed locks.
445          * Cast to signed type.
446          */
447
448         offset = (SMB_OFF_T)u_offset;
449         count = (SMB_OFF_T)u_count;
450
451         /*
452          * Deal with a very common case of count of all ones.
453          * (lock entire file).
454          */
455
456         if(count == (SMB_OFF_T)-1)
457                 count &= ~mask;
458
459         /*
460          * POSIX lock ranges cannot be negative.
461          * Fail if any combination becomes negative.
462          */
463
464         if(offset < 0 || count < 0 || (offset + count < 0)) {
465                 DEBUG(10,("posix_lock_in_range: negative range: offset = %.0f, count = %.0f. Ignoring lock.\n",
466                                 (double)offset, (double)count ));
467                 return False;
468         }
469
470         /*
471          * In this case SMB_OFF_T is 64 bits, the offset and count
472          * fit within the positive range, and the underlying
473          * system can handle 64 bit locks. Just return as the
474          * cast values are ok.
475          */
476
477 #else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
478
479         /*
480          * In this case either SMB_OFF_T is 32 bits,
481          * or the underlying system cannot handle 64 bit signed locks.
482          * Either way we have to try and mangle to fit within 31 bits.
483          * This is difficult.
484          */
485
486 #if defined(HAVE_BROKEN_FCNTL64_LOCKS)
487
488         /*
489          * SMB_OFF_T is 64 bits, but we need to use 31 bits due to
490          * broken large locking.
491          */
492
493         /*
494          * Deal with a very common case of count of all ones.
495          * (lock entire file).
496          */
497
498         if(u_count == (SMB_BIG_UINT)-1)
499                 count = 0x7FFFFFFF;
500
501         if(((u_offset >> 32) & 0xFFFFFFFF) || ((u_count >> 32) & 0xFFFFFFFF)) {
502                 DEBUG(10,("posix_lock_in_range: top 32 bits not zero. offset = %.0f, count = %.0f. Ignoring lock.\n",
503                                 (double)u_offset, (double)u_count ));
504                 /* Top 32 bits of offset or count were not zero. */
505                 return False;
506         }
507
508         /* Cast from 64 bits unsigned to 64 bits signed. */
509         offset = (SMB_OFF_T)u_offset;
510         count = (SMB_OFF_T)u_count;
511
512         /*
513          * Check if we are within the 2^31 range.
514          */
515
516         {
517                 int32 low_offset = (int32)offset;
518                 int32 low_count = (int32)count;
519
520                 if(low_offset < 0 || low_count < 0 || (low_offset + low_count < 0)) {
521                         DEBUG(10,("posix_lock_in_range: not within 2^31 range. low_offset = %d, low_count = %d. Ignoring lock.\n",
522                                         low_offset, low_count ));
523                         return False;
524                 }
525         }
526
527         /*
528          * Ok - we can map from a 64 bit number to a 31 bit lock.
529          */
530
531 #else /* HAVE_BROKEN_FCNTL64_LOCKS */
532
533         /*
534          * SMB_OFF_T is 32 bits.
535          */
536
537 #if defined(HAVE_LONGLONG)
538
539         /*
540          * SMB_BIG_UINT is 64 bits, we can do a 32 bit shift.
541          */
542
543         /*
544          * Deal with a very common case of count of all ones.
545          * (lock entire file).
546          */
547
548         if(u_count == (SMB_BIG_UINT)-1)
549                 count = 0x7FFFFFFF;
550
551         if(((u_offset >> 32) & 0xFFFFFFFF) || ((u_count >> 32) & 0xFFFFFFFF)) {
552                 DEBUG(10,("posix_lock_in_range: top 32 bits not zero. u_offset = %.0f, u_count = %.0f. Ignoring lock.\n",
553                                 (double)u_offset, (double)u_count ));
554                 return False;
555         }
556
557         /* Cast from 64 bits unsigned to 32 bits signed. */
558         offset = (SMB_OFF_T)u_offset;
559         count = (SMB_OFF_T)u_count;
560
561         /*
562          * Check if we are within the 2^31 range.
563          */
564
565         if(offset < 0 || count < 0 || (offset + count < 0)) {
566                 DEBUG(10,("posix_lock_in_range: not within 2^31 range. offset = %d, count = %d. Ignoring lock.\n",
567                                 (int)offset, (int)count ));
568                 return False;
569         }
570
571 #else /* HAVE_LONGLONG */
572
573         /*
574          * SMB_BIG_UINT and SMB_OFF_T are both 32 bits,
575          * just cast.
576          */
577
578         /*
579          * Deal with a very common case of count of all ones.
580          * (lock entire file).
581          */
582
583         if(u_count == (SMB_BIG_UINT)-1)
584                 count = 0x7FFFFFFF;
585
586         /* Cast from 32 bits unsigned to 32 bits signed. */
587         offset = (SMB_OFF_T)u_offset;
588         count = (SMB_OFF_T)u_count;
589
590         /*
591          * Check if we are within the 2^31 range.
592          */
593
594         if(offset < 0 || count < 0 || (offset + count < 0)) {
595                 DEBUG(10,("posix_lock_in_range: not within 2^31 range. offset = %d, count = %d. Ignoring lock.\n",
596                                 (int)offset, (int)count ));
597                 return False;
598         }
599
600 #endif /* HAVE_LONGLONG */
601 #endif /* LARGE_SMB_OFF_T */
602 #endif /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
603
604         /*
605          * The mapping was successful.
606          */
607
608         DEBUG(10,("posix_lock_in_range: offset_out = %.0f, count_out = %.0f\n",
609                         (double)offset, (double)count ));
610
611         *offset_out = offset;
612         *count_out = count;
613         
614         return True;
615 }
616
617 /****************************************************************************
618  POSIX function to see if a file region is locked. Returns True if the
619  region is locked, False otherwise.
620 ****************************************************************************/
621
622 BOOL is_posix_locked(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
623 {
624         SMB_OFF_T offset;
625         SMB_OFF_T count;
626         int posix_lock_type = map_posix_lock_type(fsp,lock_type);
627
628         DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
629                         fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
630
631         /*
632          * If the requested lock won't fit in the POSIX range, we will
633          * never set it, so presume it is not locked.
634          */
635
636         if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
637                 return False;
638
639         /*
640          * Note that most UNIX's can *test* for a write lock on
641          * a read-only fd, just not *set* a write lock on a read-only
642          * fd. So we don't need to use map_lock_type here.
643          */ 
644
645         return fcntl_lock(fsp->fd,SMB_F_GETLK,offset,count,posix_lock_type);
646 }
647
648 /****************************************************************************
649  POSIX function to acquire a lock. Returns True if the
650  lock could be granted, False if not.
651 ****************************************************************************/
652
653 BOOL set_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
654 {
655         SMB_OFF_T offset;
656         SMB_OFF_T count;
657         BOOL ret = True;
658         int posix_lock_type = map_posix_lock_type(fsp,lock_type);
659
660         DEBUG(5,("set_posix_lock: File %s, offset = %.0f, count = %.0f, type = %s\n",
661                         fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
662
663         /*
664          * If the requested lock won't fit in the POSIX range, we will
665          * pretend it was successful.
666          */
667
668         if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
669                 return True;
670
671         /*
672          * Note that setting multiple overlapping locks on different
673          * file descriptors will not be held separately by the kernel (POSIX
674          * braindamage), but will be merged into one continuous lock
675          * range. We cope with this case in the release_posix_lock code
676          * below. JRA.
677          */
678
679     ret = fcntl_lock(fsp->fd,SMB_F_SETLK,offset,count,posix_lock_type);
680
681         if (ret)
682                 add_posix_lock_entry(fsp,offset,count,posix_lock_type);
683
684         return ret;
685 }
686
687 /*
688  * Structure used when splitting a lock range
689  * into a POSIX lock range. Doubly linked list.
690  */
691
692 struct unlock_list {
693     struct unlock_list *next;
694     struct unlock_list *prev;
695     SMB_OFF_T start;
696     SMB_OFF_T size;
697 };
698
699 /****************************************************************************
700  Create a list of lock ranges that don't overlap a given range. Used in calculating
701  POSIX lock unlocks. This is a difficult function that requires ASCII art to
702  understand it :-).
703 ****************************************************************************/
704
705 static struct unlock_list *posix_unlock_list(TALLOC_CTX *ctx, struct unlock_list *ulhead, files_struct *fsp)
706 {
707         TDB_DATA kbuf = locking_key_fsp(fsp);
708         TDB_DATA dbuf;
709         struct posix_lock *locks;
710         size_t num_locks, i;
711
712         dbuf.dptr = NULL;
713
714         dbuf = tdb_fetch(posix_lock_tdb, kbuf);
715
716         if (!dbuf.dptr) {
717                 return ulhead;
718         }
719         
720         locks = (struct posix_lock *)dbuf.dptr;
721         num_locks = (size_t)(dbuf.dsize / sizeof(*locks));
722
723         /*
724          * Check the current lock list on this dev/inode pair.
725          * Quit if the list is deleted.
726          */
727
728         DEBUG(10,("posix_unlock_list: curr: start=%.0f,size=%.0f\n",
729                 (double)ulhead->start, (double)ulhead->size ));
730
731         for (i=0; i<num_locks && ulhead; i++) {
732
733                 struct posix_lock *lock = &locks[i];
734                 struct unlock_list *ul_curr;
735
736                 /*
737                  * Walk the unlock list, checking for overlaps. Note that
738                  * the unlock list can expand within this loop if the current
739                  * range being examined needs to be split.
740                  */
741
742                 for (ul_curr = ulhead; ul_curr;) {
743
744                         DEBUG(10,("posix_unlock_list: lock: start=%.0f,size=%.0f:",
745                                 (double)lock->start, (double)lock->size ));
746
747                         if ( (ul_curr->start >= (lock->start + lock->size)) ||
748                                  (lock->start > (ul_curr->start + ul_curr->size))) {
749
750                                 /* No overlap with this lock - leave this range alone. */
751 /*********************************************
752                                              +---------+
753                                              | ul_curr |
754                                              +---------+
755                                 +-------+
756                                 | lock  |
757                                 +-------+
758 OR....
759              +---------+
760              | ul_curr |
761              +---------+
762 **********************************************/
763
764                                 DEBUG(10,("no overlap case.\n" ));
765
766                                 ul_curr = ul_curr->next;
767
768                         } else if ( (ul_curr->start >= lock->start) &&
769                                                 (ul_curr->start + ul_curr->size <= lock->start + lock->size) ) {
770
771                                 /*
772                                  * This unlock is completely overlapped by this existing lock range
773                                  * and thus should have no effect (not be unlocked). Delete it from the list.
774                                  */
775 /*********************************************
776                 +---------+
777                 | ul_curr |
778                 +---------+
779         +---------------------------+
780         |       lock                |
781         +---------------------------+
782 **********************************************/
783                                 /* Save the next pointer */
784                                 struct unlock_list *ul_next = ul_curr->next;
785
786                                 DEBUG(10,("delete case.\n" ));
787
788                                 DLIST_REMOVE(ulhead, ul_curr);
789                                 if(ulhead == NULL)
790                                         break; /* No more list... */
791
792                                 ul_curr = ul_next;
793                                 
794                         } else if ( (ul_curr->start >= lock->start) &&
795                                                 (ul_curr->start < lock->start + lock->size) &&
796                                                 (ul_curr->start + ul_curr->size > lock->start + lock->size) ) {
797
798                                 /*
799                                  * This unlock overlaps the existing lock range at the high end.
800                                  * Truncate by moving start to existing range end and reducing size.
801                                  */
802 /*********************************************
803                 +---------------+
804                 | ul_curr       |
805                 +---------------+
806         +---------------+
807         |    lock       |
808         +---------------+
809 BECOMES....
810                         +-------+
811                         |ul_curr|
812                         +-------+
813 **********************************************/
814
815                                 ul_curr->size = (ul_curr->start + ul_curr->size) - (lock->start + lock->size);
816                                 ul_curr->start = lock->start + lock->size;
817
818                                 DEBUG(10,("truncate high case: start=%.0f,size=%.0f\n",
819                                                                 (double)ul_curr->start, (double)ul_curr->size ));
820
821                                 ul_curr = ul_curr->next;
822
823                         } else if ( (ul_curr->start < lock->start) &&
824                                                 (ul_curr->start + ul_curr->size > lock->start) ) {
825
826                                 /*
827                                  * This unlock overlaps the existing lock range at the low end.
828                                  * Truncate by reducing size.
829                                  */
830 /*********************************************
831    +---------------+
832    | ul_curr       |
833    +---------------+
834            +---------------+
835            |    lock       |
836            +---------------+
837 BECOMES....
838    +-------+
839    |ul_curr|
840    +-------+
841 **********************************************/
842
843                                 ul_curr->size = lock->start - ul_curr->start;
844
845                                 DEBUG(10,("truncate low case: start=%.0f,size=%.0f\n",
846                                                                 (double)ul_curr->start, (double)ul_curr->size ));
847
848                                 ul_curr = ul_curr->next;
849                 
850                         } else if ( (ul_curr->start < lock->start) &&
851                                                 (ul_curr->start + ul_curr->size > lock->start + lock->size) ) {
852                                 /*
853                                  * Worst case scenario. Unlock request completely overlaps an existing
854                                  * lock range. Split the request into two, push the new (upper) request
855                                  * into the dlink list, and continue with the entry after ul_new (as we
856                                  * know that ul_new will not overlap with this lock).
857                                  */
858 /*********************************************
859         +---------------------------+
860         |       ul_curr             |
861         +---------------------------+
862                 +---------+
863                 | lock    |
864                 +---------+
865 BECOMES.....
866         +-------+         +---------+
867         |ul_curr|         |ul_new   |
868         +-------+         +---------+
869 **********************************************/
870                                 struct unlock_list *ul_new = (struct unlock_list *)talloc(ctx,
871                                                                                                         sizeof(struct unlock_list));
872
873                                 if(ul_new == NULL) {
874                                         DEBUG(0,("posix_unlock_list: talloc fail.\n"));
875                                         return NULL; /* The talloc_destroy takes care of cleanup. */
876                                 }
877
878                                 ZERO_STRUCTP(ul_new);
879                                 ul_new->start = lock->start + lock->size;
880                                 ul_new->size = ul_curr->start + ul_curr->size - ul_new->start;
881
882                                 /* Add into the dlink list after the ul_curr point - NOT at ulhead. */
883                                 DLIST_ADD(ul_curr, ul_new);
884
885                                 /* Truncate the ul_curr. */
886                                 ul_curr->size = lock->start - ul_curr->start;
887
888                                 DEBUG(10,("split case: curr: start=%.0f,size=%.0f \
889 new: start=%.0f,size=%.0f\n", (double)ul_curr->start, (double)ul_curr->size,
890                                                                 (double)ul_new->start, (double)ul_new->size ));
891
892                                 ul_curr = ul_new->next;
893
894                         } else {
895
896                                 /*
897                                  * This logic case should never happen. Ensure this is the
898                                  * case by forcing an abort.... Remove in production.
899                                  */
900
901                                 smb_panic("logic flaw in cases...\n");
902                         }
903                 } /* end for ( ul_curr = ulhead; ul_curr;) */
904         } /* end for (i=0; i<num_locks && ul_head; i++) */
905
906         if (dbuf.dptr)
907                 free(dbuf.dptr);
908         
909         return ulhead;
910 }
911
912 /****************************************************************************
913  POSIX function to release a lock. Returns True if the
914  lock could be released, False if not.
915 ****************************************************************************/
916
917 BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
918 {
919         SMB_OFF_T offset;
920         SMB_OFF_T count;
921         BOOL ret = True;
922         TALLOC_CTX *ul_ctx = NULL;
923         struct unlock_list *ulist = NULL;
924         struct unlock_list *ul = NULL;
925
926         DEBUG(5,("release_posix_lock: File %s, offset = %.0f, count = %.0f\n",
927                 fsp->fsp_name, (double)u_offset, (double)u_count ));
928
929         /*
930          * If the requested lock won't fit in the POSIX range, we will
931          * pretend it was successful.
932          */
933
934         if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
935                 return True;
936
937         /*
938          * We treat this as one unlock request for POSIX accounting purposes even
939          * if it may have been split into multiple smaller POSIX unlock ranges.
940          */ 
941
942         delete_posix_lock_entry(fsp, offset, count);
943
944         if ((ul_ctx = talloc_init()) == NULL) {
945         DEBUG(0,("release_posix_lock: unable to init talloc context.\n"));
946                 return True; /* Not a fatal error. */
947         }
948
949         if ((ul = (struct unlock_list *)talloc(ul_ctx, sizeof(struct unlock_list))) == NULL) {
950                 DEBUG(0,("release_posix_lock: unable to talloc unlock list.\n"));
951                 talloc_destroy(ul_ctx);
952                 return True; /* Not a fatal error. */
953         }
954
955         /*
956          * Create the initial list entry containing the
957          * lock we want to remove.
958          */
959
960         ZERO_STRUCTP(ul);
961         ul->start = offset;
962         ul->size = count;
963
964         DLIST_ADD(ulist, ul);
965
966         /*
967          * The following call calculates if there are any
968          * overlapping locks held by this process on
969          * fd's open on the same file and creates a
970          * list of unlock ranges that will allow
971          * POSIX lock ranges to remain on the file whilst the
972          * unlocks are performed.
973          */
974
975         ulist = posix_unlock_list(ul_ctx, ulist, fsp);
976
977         /*
978          * Release the POSIX locks on the list of ranges returned.
979          */
980
981         for(; ulist; ulist = ulist->next) {
982                 offset = ulist->start;
983                 count = ulist->size;
984
985                 if(u_count == 0) {
986
987                         /*
988                          * This lock must overlap with an existing lock.
989                          * Don't do any POSIX call.
990                          */
991
992                         continue;
993                 }
994
995                 DEBUG(5,("release_posix_lock: Real unlock: offset = %.0f, count = %.0f\n",
996                         (double)offset, (double)count ));
997
998                 if (!fcntl_lock(fsp->fd,SMB_F_SETLK,offset,count,F_UNLCK))
999                         ret = False;
1000         }
1001
1002         talloc_destroy(ul_ctx);
1003
1004         return ret;
1005 }
1006
1007 /****************************************************************************
1008  Remove all lock entries for a specific dev/inode pair from the tdb.
1009 ****************************************************************************/
1010
1011 static void delete_posix_lock_entries(files_struct *fsp)
1012 {
1013         TDB_DATA kbuf = locking_key_fsp(fsp);
1014
1015         if (tdb_delete(posix_lock_tdb, kbuf) == -1)
1016                 DEBUG(0,("delete_close_entries: tdb_delete fail !\n"));
1017 }
1018
1019 /****************************************************************************
1020  Debug function.
1021 ****************************************************************************/
1022
1023 static void dump_entry(struct posix_lock *pl)
1024 {
1025         DEBUG(10,("entry: start=%.0f, size=%.0f, type=%d, fd=%i\n",
1026                 (double)pl->start, (double)pl->size, (int)pl->lock_type, pl->fd ));
1027 }
1028
1029 /****************************************************************************
1030  Remove any locks on this fd. Called from file_close().
1031 ****************************************************************************/
1032
1033 void posix_locking_close_file(files_struct *fsp)
1034 {
1035         struct posix_lock *entries = NULL;
1036         size_t count, i;
1037
1038         /*
1039          * Optimization for the common case where we are the only
1040          * opener of a file. If all fd entries are our own, we don't
1041          * need to explicitly release all the locks via the POSIX functions,
1042          * we can just remove all the entries in the tdb and allow the
1043          * close to remove the real locks.
1044          */
1045
1046         count = get_posix_lock_entries(fsp, &entries);
1047
1048         if (count == 0) {
1049                 DEBUG(10,("posix_locking_close_file: file %s has no outstanding locks.\n", fsp->fsp_name ));
1050                 return;
1051         }
1052
1053         for (i = 0; i < count; i++) {
1054                 if (entries[i].fd != fsp->fd )
1055                         break;
1056
1057                 dump_entry(&entries[i]);
1058         }
1059
1060         if (i == count) {
1061                 /* All locks are ours. */
1062                 DEBUG(10,("posix_locking_close_file: file %s has %u outstanding locks, but all on one fd.\n", 
1063                         fsp->fsp_name, (unsigned int)count ));
1064                 free((char *)entries);
1065                 delete_posix_lock_entries(fsp);
1066                 return;
1067         }
1068
1069         /*
1070          * Difficult case. We need to delete all our locks, whilst leaving
1071          * all other POSIX locks in place.
1072          */
1073
1074         for (i = 0; i < count; i++) {
1075                 struct posix_lock *pl = &entries[i];
1076                 release_posix_lock(fsp, (SMB_BIG_UINT)pl->start, (SMB_BIG_UINT)pl->size );
1077         }
1078         free((char *)entries);
1079 }
1080
1081 /*******************************************************************
1082  Create the in-memory POSIX lock databases.
1083 ********************************************************************/
1084
1085 BOOL posix_locking_init(void)
1086 {
1087         if (posix_lock_tdb && posix_pending_close_tdb)
1088                 return True;
1089
1090         if (!posix_lock_tdb)
1091                 posix_lock_tdb = tdb_open(NULL, 0, TDB_CLEAR_IF_FIRST,
1092                     O_RDWR|O_CREAT, 0644);
1093     if (!posix_lock_tdb) {
1094         DEBUG(0,("Failed to open POSIX byte range locking database.\n"));
1095                 return False;
1096     }
1097         if (!posix_pending_close_tdb)
1098                 posix_pending_close_tdb = tdb_open(NULL, 0, TDB_CLEAR_IF_FIRST,
1099                     O_RDWR|O_CREAT, 0644);
1100     if (!posix_pending_close_tdb) {
1101         DEBUG(0,("Failed to open POSIX pending close database.\n"));
1102                 return False;
1103     }
1104
1105         return True;
1106 }
1107
1108 /*******************************************************************
1109  Delete the in-memory POSIX lock databases.
1110 ********************************************************************/
1111
1112 BOOL posix_locking_end(void)
1113 {
1114     if (posix_lock_tdb && tdb_close(posix_lock_tdb) != 0)
1115                 return False;
1116     if (posix_pending_close_tdb && tdb_close(posix_pending_close_tdb) != 0)
1117                 return False;
1118         return True;
1119 }