Make sure we don't clobber the stack when response consists of the empty
[Samba/gebeck_regimport.git] / source3 / locking / posix.c
blob6173c80b2fd96587ef9c893cf9826487cb5e24f9
1 /*
2 Unix SMB/CIFS implementation.
3 Locking functions
4 Copyright (C) Jeremy Allison 1992-2000
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 Revision History:
22 POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
25 #include "includes.h"
28 * The POSIX locking database handle.
31 static TDB_CONTEXT *posix_lock_tdb;
34 * The pending close database handle.
37 static TDB_CONTEXT *posix_pending_close_tdb;
40 * The data in POSIX lock records is an unsorted linear array of these
41 * records. It is unnecessary to store the count as tdb provides the
42 * size of the record.
45 struct posix_lock {
46 int fd;
47 SMB_OFF_T start;
48 SMB_OFF_T size;
49 int lock_type;
53 * The data in POSIX pending close records is an unsorted linear array of int
54 * records. It is unnecessary to store the count as tdb provides the
55 * size of the record.
58 /* The key used in both the POSIX databases. */
60 struct posix_lock_key {
61 SMB_DEV_T device;
62 SMB_INO_T inode;
63 };
65 /*******************************************************************
66 Form a static locking key for a dev/inode pair.
67 ******************************************************************/
69 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
71 static struct posix_lock_key key;
72 TDB_DATA kbuf;
74 memset(&key, '\0', sizeof(key));
75 key.device = dev;
76 key.inode = inode;
77 kbuf.dptr = (char *)&key;
78 kbuf.dsize = sizeof(key);
79 return kbuf;
82 /*******************************************************************
83 Convenience function to get a key from an fsp.
84 ******************************************************************/
86 static TDB_DATA locking_key_fsp(files_struct *fsp)
88 return locking_key(fsp->dev, fsp->inode);
91 /****************************************************************************
92 Add an fd to the pending close tdb.
93 ****************************************************************************/
95 static BOOL add_fd_to_close_entry(files_struct *fsp)
97 TDB_DATA kbuf = locking_key_fsp(fsp);
98 TDB_DATA dbuf;
99 char *tp;
101 dbuf.dptr = NULL;
103 dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
105 tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(int));
106 if (!tp) {
107 DEBUG(0,("add_fd_to_close_entry: Realloc fail !\n"));
108 SAFE_FREE(dbuf.dptr);
109 return False;
110 } else
111 dbuf.dptr = tp;
113 memcpy(dbuf.dptr + dbuf.dsize, &fsp->fd, sizeof(int));
114 dbuf.dsize += sizeof(int);
116 if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
117 DEBUG(0,("add_fd_to_close_entry: tdb_store fail !\n"));
120 SAFE_FREE(dbuf.dptr);
121 return True;
124 /****************************************************************************
125 Remove all fd entries for a specific dev/inode pair from the tdb.
126 ****************************************************************************/
128 static void delete_close_entries(files_struct *fsp)
130 TDB_DATA kbuf = locking_key_fsp(fsp);
132 if (tdb_delete(posix_pending_close_tdb, kbuf) == -1)
133 DEBUG(0,("delete_close_entries: tdb_delete fail !\n"));
136 /****************************************************************************
137 Get the array of POSIX pending close records for an open fsp. Caller must
138 free. Returns number of entries.
139 ****************************************************************************/
141 static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries)
143 TDB_DATA kbuf = locking_key_fsp(fsp);
144 TDB_DATA dbuf;
145 size_t count = 0;
147 *entries = NULL;
148 dbuf.dptr = NULL;
150 dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
152 if (!dbuf.dptr) {
153 return 0;
156 *entries = (int *)dbuf.dptr;
157 count = (size_t)(dbuf.dsize / sizeof(int));
159 return count;
162 /****************************************************************************
163 Get the array of POSIX locks for an fsp. Caller must free. Returns
164 number of entries.
165 ****************************************************************************/
167 static size_t get_posix_lock_entries(files_struct *fsp, struct posix_lock **entries)
169 TDB_DATA kbuf = locking_key_fsp(fsp);
170 TDB_DATA dbuf;
171 size_t count = 0;
173 *entries = NULL;
175 dbuf.dptr = NULL;
177 dbuf = tdb_fetch(posix_lock_tdb, kbuf);
179 if (!dbuf.dptr) {
180 return 0;
183 *entries = (struct posix_lock *)dbuf.dptr;
184 count = (size_t)(dbuf.dsize / sizeof(struct posix_lock));
186 return count;
189 /****************************************************************************
190 Deal with pending closes needed by POSIX locking support.
191 Note that posix_locking_close_file() is expected to have been called
192 to delete all locks on this fsp before this function is called.
193 ****************************************************************************/
195 int fd_close_posix(struct connection_struct *conn, files_struct *fsp)
197 int saved_errno = 0;
198 int ret;
199 size_t count, i;
200 struct posix_lock *entries = NULL;
201 int *fd_array = NULL;
202 BOOL locks_on_other_fds = False;
204 if (!lp_posix_locking(SNUM(conn))) {
206 * No POSIX to worry about, just close.
208 ret = SMB_VFS_CLOSE(fsp,fsp->fd);
209 fsp->fd = -1;
210 return ret;
214 * Get the number of outstanding POSIX locks on this dev/inode pair.
217 count = get_posix_lock_entries(fsp, &entries);
220 * Check if there are any outstanding locks belonging to
221 * other fd's. This should never be the case if posix_locking_close_file()
222 * has been called first, but it never hurts to be *sure*.
225 for (i = 0; i < count; i++) {
226 if (entries[i].fd != fsp->fd) {
227 locks_on_other_fds = True;
228 break;
232 if (locks_on_other_fds) {
235 * There are outstanding locks on this dev/inode pair on other fds.
236 * Add our fd to the pending close tdb and set fsp->fd to -1.
239 if (!add_fd_to_close_entry(fsp)) {
240 SAFE_FREE(entries);
241 return False;
244 SAFE_FREE(entries);
245 fsp->fd = -1;
246 return 0;
249 SAFE_FREE(entries);
252 * No outstanding POSIX locks. Get the pending close fd's
253 * from the tdb and close them all.
256 count = get_posix_pending_close_entries(fsp, &fd_array);
258 if (count) {
259 DEBUG(10,("fd_close_posix: doing close on %u fd's.\n", (unsigned int)count ));
261 for(i = 0; i < count; i++) {
262 if (SMB_VFS_CLOSE(fsp,fd_array[i]) == -1) {
263 saved_errno = errno;
268 * Delete all fd's stored in the tdb
269 * for this dev/inode pair.
272 delete_close_entries(fsp);
275 SAFE_FREE(fd_array);
278 * Finally close the fd associated with this fsp.
281 ret = SMB_VFS_CLOSE(fsp,fsp->fd);
283 if (saved_errno != 0) {
284 errno = saved_errno;
285 ret = -1;
288 fsp->fd = -1;
290 return ret;
293 /****************************************************************************
294 Debugging aid :-).
295 ****************************************************************************/
297 static const char *posix_lock_type_name(int lock_type)
299 return (lock_type == F_RDLCK) ? "READ" : "WRITE";
302 /****************************************************************************
303 Delete a POSIX lock entry by index number. Used if the tdb add succeeds, but
304 then the POSIX fcntl lock fails.
305 ****************************************************************************/
307 static BOOL delete_posix_lock_entry_by_index(files_struct *fsp, size_t entry)
309 TDB_DATA kbuf = locking_key_fsp(fsp);
310 TDB_DATA dbuf;
311 struct posix_lock *locks;
312 size_t count;
314 dbuf.dptr = NULL;
316 dbuf = tdb_fetch(posix_lock_tdb, kbuf);
318 if (!dbuf.dptr) {
319 DEBUG(10,("delete_posix_lock_entry_by_index: tdb_fetch failed !\n"));
320 goto fail;
323 count = (size_t)(dbuf.dsize / sizeof(struct posix_lock));
324 locks = (struct posix_lock *)dbuf.dptr;
326 if (count == 1) {
327 tdb_delete(posix_lock_tdb, kbuf);
328 } else {
329 if (entry < count-1) {
330 memmove(&locks[entry], &locks[entry+1], sizeof(*locks)*((count-1) - entry));
332 dbuf.dsize -= sizeof(*locks);
333 tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE);
336 SAFE_FREE(dbuf.dptr);
338 return True;
340 fail:
342 SAFE_FREE(dbuf.dptr);
343 return False;
346 /****************************************************************************
347 Add an entry into the POSIX locking tdb. We return the index number of the
348 added lock (used in case we need to delete *exactly* this entry). Returns
349 False on fail, True on success.
350 ****************************************************************************/
352 static BOOL add_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size, int lock_type, size_t *pentry_num)
354 TDB_DATA kbuf = locking_key_fsp(fsp);
355 TDB_DATA dbuf;
356 struct posix_lock pl;
357 char *tp;
359 dbuf.dptr = NULL;
361 dbuf = tdb_fetch(posix_lock_tdb, kbuf);
363 *pentry_num = (size_t)(dbuf.dsize / sizeof(pl));
366 * Add new record.
369 pl.fd = fsp->fd;
370 pl.start = start;
371 pl.size = size;
372 pl.lock_type = lock_type;
374 tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(pl));
375 if (!tp) {
376 DEBUG(0,("add_posix_lock_entry: Realloc fail !\n"));
377 goto fail;
378 } else
379 dbuf.dptr = tp;
381 memcpy(dbuf.dptr + dbuf.dsize, &pl, sizeof(pl));
382 dbuf.dsize += sizeof(pl);
384 if (tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
385 DEBUG(0,("add_posix_lock: Failed to add lock entry on file %s\n", fsp->fsp_name));
386 goto fail;
389 SAFE_FREE(dbuf.dptr);
391 DEBUG(10,("add_posix_lock: File %s: type = %s: start=%.0f size=%.0f: dev=%.0f inode=%.0f\n",
392 fsp->fsp_name, posix_lock_type_name(lock_type), (double)start, (double)size,
393 (double)fsp->dev, (double)fsp->inode ));
395 return True;
397 fail:
399 SAFE_FREE(dbuf.dptr);
400 return False;
403 /****************************************************************************
404 Calculate if locks have any overlap at all.
405 ****************************************************************************/
407 static BOOL does_lock_overlap(SMB_OFF_T start1, SMB_OFF_T size1, SMB_OFF_T start2, SMB_OFF_T size2)
409 if (start1 >= start2 && start1 <= start2 + size2)
410 return True;
412 if (start1 < start2 && start1 + size1 > start2)
413 return True;
415 return False;
418 /****************************************************************************
419 Delete an entry from the POSIX locking tdb. Returns a copy of the entry being
420 deleted and the number of records that are overlapped by this one, or -1 on error.
421 ****************************************************************************/
423 static int delete_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size, struct posix_lock *pl)
425 TDB_DATA kbuf = locking_key_fsp(fsp);
426 TDB_DATA dbuf;
427 struct posix_lock *locks;
428 size_t i, count;
429 BOOL found = False;
430 int num_overlapping_records = 0;
432 dbuf.dptr = NULL;
434 dbuf = tdb_fetch(posix_lock_tdb, kbuf);
436 if (!dbuf.dptr) {
437 DEBUG(10,("delete_posix_lock_entry: tdb_fetch failed !\n"));
438 goto fail;
441 /* There are existing locks - find a match. */
442 locks = (struct posix_lock *)dbuf.dptr;
443 count = (size_t)(dbuf.dsize / sizeof(*locks));
446 * Search for and delete the first record that matches the
447 * unlock criteria.
450 for (i=0; i<count; i++) {
451 struct posix_lock *entry = &locks[i];
453 if (entry->fd == fsp->fd &&
454 entry->start == start &&
455 entry->size == size) {
457 /* Make a copy if requested. */
458 if (pl)
459 *pl = *entry;
461 /* Found it - delete it. */
462 if (count == 1) {
463 tdb_delete(posix_lock_tdb, kbuf);
464 } else {
465 if (i < count-1) {
466 memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i));
468 dbuf.dsize -= sizeof(*locks);
469 tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE);
471 count--;
472 found = True;
473 break;
477 if (!found)
478 goto fail;
481 * Count the number of entries that are
482 * overlapped by this unlock request.
485 for (i = 0; i < count; i++) {
486 struct posix_lock *entry = &locks[i];
488 if (fsp->fd == entry->fd &&
489 does_lock_overlap( start, size, entry->start, entry->size))
490 num_overlapping_records++;
493 DEBUG(10,("delete_posix_lock_entry: type = %s: start=%.0f size=%.0f, num_records = %d\n",
494 posix_lock_type_name(pl->lock_type), (double)pl->start, (double)pl->size,
495 (unsigned int)num_overlapping_records ));
497 SAFE_FREE(dbuf.dptr);
499 return num_overlapping_records;
501 fail:
503 SAFE_FREE(dbuf.dptr);
504 return -1;
507 /****************************************************************************
508 Utility function to map a lock type correctly depending on the open
509 mode of a file.
510 ****************************************************************************/
512 static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type)
514 if((lock_type == WRITE_LOCK) && !fsp->can_write) {
516 * Many UNIX's cannot get a write lock on a file opened read-only.
517 * Win32 locking semantics allow this.
518 * Do the best we can and attempt a read-only lock.
520 DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n"));
521 return F_RDLCK;
522 } else if((lock_type == READ_LOCK) && !fsp->can_read) {
524 * Ditto for read locks on write only files.
526 DEBUG(10,("map_posix_lock_type: Changing read lock to write due to write-only file.\n"));
527 return F_WRLCK;
531 * This return should be the most normal, as we attempt
532 * to always open files read/write.
535 return (lock_type == READ_LOCK) ? F_RDLCK : F_WRLCK;
538 /****************************************************************************
539 Check to see if the given unsigned lock range is within the possible POSIX
540 range. Modifies the given args to be in range if possible, just returns
541 False if not.
542 ****************************************************************************/
544 static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
545 SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
547 SMB_OFF_T offset = (SMB_OFF_T)u_offset;
548 SMB_OFF_T count = (SMB_OFF_T)u_count;
551 * For the type of system we are, attempt to
552 * find the maximum positive lock offset as an SMB_OFF_T.
555 #if defined(MAX_POSITIVE_LOCK_OFFSET) /* Some systems have arbitrary limits. */
557 SMB_OFF_T max_positive_lock_offset = (MAX_POSITIVE_LOCK_OFFSET);
559 #elif defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
562 * In this case SMB_OFF_T is 64 bits,
563 * and the underlying system can handle 64 bit signed locks.
566 SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4);
567 SMB_OFF_T mask = (mask2<<1);
568 SMB_OFF_T max_positive_lock_offset = ~mask;
570 #else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
573 * In this case either SMB_OFF_T is 32 bits,
574 * or the underlying system cannot handle 64 bit signed locks.
575 * All offsets & counts must be 2^31 or less.
578 SMB_OFF_T max_positive_lock_offset = 0x7FFFFFFF;
580 #endif /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
583 * POSIX locks of length zero mean lock to end-of-file.
584 * Win32 locks of length zero are point probes. Ignore
585 * any Win32 locks of length zero. JRA.
588 if (count == (SMB_OFF_T)0) {
589 DEBUG(10,("posix_lock_in_range: count = 0, ignoring.\n"));
590 return False;
594 * If the given offset was > max_positive_lock_offset then we cannot map this at all
595 * ignore this lock.
598 if (u_offset & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
599 DEBUG(10,("posix_lock_in_range: (offset = %.0f) offset > %.0f and we cannot handle this. Ignoring lock.\n",
600 (double)u_offset, (double)((SMB_BIG_UINT)max_positive_lock_offset) ));
601 return False;
605 * We must truncate the count to less than max_positive_lock_offset.
608 if (u_count & ~((SMB_BIG_UINT)max_positive_lock_offset))
609 count = max_positive_lock_offset;
612 * Truncate count to end at max lock offset.
615 if (offset + count < 0 || offset + count > max_positive_lock_offset)
616 count = max_positive_lock_offset - offset;
619 * If we ate all the count, ignore this lock.
622 if (count == 0) {
623 DEBUG(10,("posix_lock_in_range: Count = 0. Ignoring lock u_offset = %.0f, u_count = %.0f\n",
624 (double)u_offset, (double)u_count ));
625 return False;
629 * The mapping was successful.
632 DEBUG(10,("posix_lock_in_range: offset_out = %.0f, count_out = %.0f\n",
633 (double)offset, (double)count ));
635 *offset_out = offset;
636 *count_out = count;
638 return True;
641 /****************************************************************************
642 Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and
643 broken NFS implementations.
644 ****************************************************************************/
646 static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
648 int ret;
650 DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fd,op,(double)offset,(double)count,type));
652 ret = SMB_VFS_LOCK(fsp,fsp->fd,op,offset,count,type);
654 if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
656 DEBUG(0,("posix_fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n",
657 (double)offset,(double)count));
658 DEBUG(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
659 DEBUG(0,("on 32 bit NFS mounted file systems.\n"));
662 * If the offset is > 0x7FFFFFFF then this will cause problems on
663 * 32 bit NFS mounted filesystems. Just ignore it.
666 if (offset & ~((SMB_OFF_T)0x7fffffff)) {
667 DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
668 return True;
671 if (count & ~((SMB_OFF_T)0x7fffffff)) {
672 /* 32 bit NFS file system, retry with smaller offset */
673 DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
674 errno = 0;
675 count &= 0x7fffffff;
676 ret = SMB_VFS_LOCK(fsp,fsp->fd,op,offset,count,type);
680 DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
682 return ret;
685 /****************************************************************************
686 POSIX function to see if a file region is locked. Returns True if the
687 region is locked, False otherwise.
688 ****************************************************************************/
690 BOOL is_posix_locked(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
692 SMB_OFF_T offset;
693 SMB_OFF_T count;
694 int posix_lock_type = map_posix_lock_type(fsp,lock_type);
696 DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
697 fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
700 * If the requested lock won't fit in the POSIX range, we will
701 * never set it, so presume it is not locked.
704 if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
705 return False;
708 * Note that most UNIX's can *test* for a write lock on
709 * a read-only fd, just not *set* a write lock on a read-only
710 * fd. So we don't need to use map_lock_type here.
713 return posix_fcntl_lock(fsp,SMB_F_GETLK,offset,count,posix_lock_type);
717 * Structure used when splitting a lock range
718 * into a POSIX lock range. Doubly linked list.
721 struct lock_list {
722 struct lock_list *next;
723 struct lock_list *prev;
724 SMB_OFF_T start;
725 SMB_OFF_T size;
728 /****************************************************************************
729 Create a list of lock ranges that don't overlap a given range. Used in calculating
730 POSIX locks and unlocks. This is a difficult function that requires ASCII art to
731 understand it :-).
732 ****************************************************************************/
734 static struct lock_list *posix_lock_list(TALLOC_CTX *ctx, struct lock_list *lhead, files_struct *fsp)
736 TDB_DATA kbuf = locking_key_fsp(fsp);
737 TDB_DATA dbuf;
738 struct posix_lock *locks;
739 size_t num_locks, i;
741 dbuf.dptr = NULL;
743 dbuf = tdb_fetch(posix_lock_tdb, kbuf);
745 if (!dbuf.dptr)
746 return lhead;
748 locks = (struct posix_lock *)dbuf.dptr;
749 num_locks = (size_t)(dbuf.dsize / sizeof(*locks));
752 * Check the current lock list on this dev/inode pair.
753 * Quit if the list is deleted.
756 DEBUG(10,("posix_lock_list: curr: start=%.0f,size=%.0f\n",
757 (double)lhead->start, (double)lhead->size ));
759 for (i=0; i<num_locks && lhead; i++) {
761 struct posix_lock *lock = &locks[i];
762 struct lock_list *l_curr;
765 * Walk the lock list, checking for overlaps. Note that
766 * the lock list can expand within this loop if the current
767 * range being examined needs to be split.
770 for (l_curr = lhead; l_curr;) {
772 DEBUG(10,("posix_lock_list: lock: fd=%d: start=%.0f,size=%.0f:type=%s", lock->fd,
773 (double)lock->start, (double)lock->size, posix_lock_type_name(lock->lock_type) ));
775 if ( (l_curr->start >= (lock->start + lock->size)) ||
776 (lock->start >= (l_curr->start + l_curr->size))) {
778 /* No overlap with this lock - leave this range alone. */
779 /*********************************************
780 +---------+
781 | l_curr |
782 +---------+
783 +-------+
784 | lock |
785 +-------+
786 OR....
787 +---------+
788 | l_curr |
789 +---------+
790 **********************************************/
792 DEBUG(10,("no overlap case.\n" ));
794 l_curr = l_curr->next;
796 } else if ( (l_curr->start >= lock->start) &&
797 (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
800 * This unlock is completely overlapped by this existing lock range
801 * and thus should have no effect (not be unlocked). Delete it from the list.
803 /*********************************************
804 +---------+
805 | l_curr |
806 +---------+
807 +---------------------------+
808 | lock |
809 +---------------------------+
810 **********************************************/
811 /* Save the next pointer */
812 struct lock_list *ul_next = l_curr->next;
814 DEBUG(10,("delete case.\n" ));
816 DLIST_REMOVE(lhead, l_curr);
817 if(lhead == NULL)
818 break; /* No more list... */
820 l_curr = ul_next;
822 } else if ( (l_curr->start >= lock->start) &&
823 (l_curr->start < lock->start + lock->size) &&
824 (l_curr->start + l_curr->size > lock->start + lock->size) ) {
827 * This unlock overlaps the existing lock range at the high end.
828 * Truncate by moving start to existing range end and reducing size.
830 /*********************************************
831 +---------------+
832 | l_curr |
833 +---------------+
834 +---------------+
835 | lock |
836 +---------------+
837 BECOMES....
838 +-------+
839 | l_curr|
840 +-------+
841 **********************************************/
843 l_curr->size = (l_curr->start + l_curr->size) - (lock->start + lock->size);
844 l_curr->start = lock->start + lock->size;
846 DEBUG(10,("truncate high case: start=%.0f,size=%.0f\n",
847 (double)l_curr->start, (double)l_curr->size ));
849 l_curr = l_curr->next;
851 } else if ( (l_curr->start < lock->start) &&
852 (l_curr->start + l_curr->size > lock->start) &&
853 (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
856 * This unlock overlaps the existing lock range at the low end.
857 * Truncate by reducing size.
859 /*********************************************
860 +---------------+
861 | l_curr |
862 +---------------+
863 +---------------+
864 | lock |
865 +---------------+
866 BECOMES....
867 +-------+
868 | l_curr|
869 +-------+
870 **********************************************/
872 l_curr->size = lock->start - l_curr->start;
874 DEBUG(10,("truncate low case: start=%.0f,size=%.0f\n",
875 (double)l_curr->start, (double)l_curr->size ));
877 l_curr = l_curr->next;
879 } else if ( (l_curr->start < lock->start) &&
880 (l_curr->start + l_curr->size > lock->start + lock->size) ) {
882 * Worst case scenario. Unlock request completely overlaps an existing
883 * lock range. Split the request into two, push the new (upper) request
884 * into the dlink list, and continue with the entry after ul_new (as we
885 * know that ul_new will not overlap with this lock).
887 /*********************************************
888 +---------------------------+
889 | l_curr |
890 +---------------------------+
891 +---------+
892 | lock |
893 +---------+
894 BECOMES.....
895 +-------+ +---------+
896 | l_curr| | l_new |
897 +-------+ +---------+
898 **********************************************/
899 struct lock_list *l_new = (struct lock_list *)talloc(ctx,
900 sizeof(struct lock_list));
902 if(l_new == NULL) {
903 DEBUG(0,("posix_lock_list: talloc fail.\n"));
904 return NULL; /* The talloc_destroy takes care of cleanup. */
907 ZERO_STRUCTP(l_new);
908 l_new->start = lock->start + lock->size;
909 l_new->size = l_curr->start + l_curr->size - l_new->start;
911 /* Truncate the l_curr. */
912 l_curr->size = lock->start - l_curr->start;
914 DEBUG(10,("split case: curr: start=%.0f,size=%.0f \
915 new: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size,
916 (double)l_new->start, (double)l_new->size ));
919 * Add into the dlink list after the l_curr point - NOT at lhead.
920 * Note we can't use DLINK_ADD here as this inserts at the head of the given list.
923 l_new->prev = l_curr;
924 l_new->next = l_curr->next;
925 l_curr->next = l_new;
927 /* And move after the link we added. */
928 l_curr = l_new->next;
930 } else {
933 * This logic case should never happen. Ensure this is the
934 * case by forcing an abort.... Remove in production.
936 pstring msg;
938 slprintf(msg, sizeof(msg)-1, "logic flaw in cases: l_curr: start = %.0f, size = %.0f : \
939 lock: start = %.0f, size = %.0f\n", (double)l_curr->start, (double)l_curr->size, (double)lock->start, (double)lock->size );
941 smb_panic(msg);
943 } /* end for ( l_curr = lhead; l_curr;) */
944 } /* end for (i=0; i<num_locks && ul_head; i++) */
946 SAFE_FREE(dbuf.dptr);
948 return lhead;
951 /****************************************************************************
952 POSIX function to acquire a lock. Returns True if the
953 lock could be granted, False if not.
954 ****************************************************************************/
956 BOOL set_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
958 SMB_OFF_T offset;
959 SMB_OFF_T count;
960 BOOL ret = True;
961 size_t entry_num = 0;
962 size_t lock_count;
963 TALLOC_CTX *l_ctx = NULL;
964 struct lock_list *llist = NULL;
965 struct lock_list *ll = NULL;
966 int posix_lock_type = map_posix_lock_type(fsp,lock_type);
968 DEBUG(5,("set_posix_lock: File %s, offset = %.0f, count = %.0f, type = %s\n",
969 fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
972 * If the requested lock won't fit in the POSIX range, we will
973 * pretend it was successful.
976 if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
977 return True;
980 * Windows is very strange. It allows read locks to be overlayed
981 * (even over a write lock), but leaves the write lock in force until the first
982 * unlock. It also reference counts the locks. This means the following sequence :
984 * process1 process2
985 * ------------------------------------------------------------------------
986 * WRITE LOCK : start = 2, len = 10
987 * READ LOCK: start =0, len = 10 - FAIL
988 * READ LOCK : start = 0, len = 14
989 * READ LOCK: start =0, len = 10 - FAIL
990 * UNLOCK : start = 2, len = 10
991 * READ LOCK: start =0, len = 10 - OK
993 * Under POSIX, the same sequence in steps 1 and 2 would not be reference counted, but
994 * would leave a single read lock over the 0-14 region. In order to
995 * re-create Windows semantics mapped to POSIX locks, we create multiple TDB
996 * entries, one for each overlayed lock request. We are guarenteed by the brlock
997 * semantics that if a write lock is added, then it will be first in the array.
1000 if ((l_ctx = talloc_init("set_posix_lock")) == NULL) {
1001 DEBUG(0,("set_posix_lock: unable to init talloc context.\n"));
1002 return True; /* Not a fatal error. */
1005 if ((ll = (struct lock_list *)talloc(l_ctx, sizeof(struct lock_list))) == NULL) {
1006 DEBUG(0,("set_posix_lock: unable to talloc unlock list.\n"));
1007 talloc_destroy(l_ctx);
1008 return True; /* Not a fatal error. */
1012 * Create the initial list entry containing the
1013 * lock we want to add.
1016 ZERO_STRUCTP(ll);
1017 ll->start = offset;
1018 ll->size = count;
1020 DLIST_ADD(llist, ll);
1023 * The following call calculates if there are any
1024 * overlapping locks held by this process on
1025 * fd's open on the same file and splits this list
1026 * into a list of lock ranges that do not overlap with existing
1027 * POSIX locks.
1030 llist = posix_lock_list(l_ctx, llist, fsp);
1033 * Now we have the list of ranges to lock it is safe to add the
1034 * entry into the POSIX lock tdb. We take note of the entry we
1035 * added here in case we have to remove it on POSIX lock fail.
1038 if (!add_posix_lock_entry(fsp,offset,count,posix_lock_type,&entry_num)) {
1039 DEBUG(0,("set_posix_lock: Unable to create posix lock entry !\n"));
1040 talloc_destroy(l_ctx);
1041 return False;
1045 * Add the POSIX locks on the list of ranges returned.
1046 * As the lock is supposed to be added atomically, we need to
1047 * back out all the locks if any one of these calls fail.
1050 for (lock_count = 0, ll = llist; ll; ll = ll->next, lock_count++) {
1051 offset = ll->start;
1052 count = ll->size;
1054 DEBUG(5,("set_posix_lock: Real lock: Type = %s: offset = %.0f, count = %.0f\n",
1055 posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
1057 if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) {
1058 DEBUG(5,("set_posix_lock: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
1059 posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
1060 ret = False;
1061 break;
1065 if (!ret) {
1068 * Back out all the POSIX locks we have on fail.
1071 for (ll = llist; lock_count; ll = ll->next, lock_count--) {
1072 offset = ll->start;
1073 count = ll->size;
1075 DEBUG(5,("set_posix_lock: Backing out locks: Type = %s: offset = %.0f, count = %.0f\n",
1076 posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
1078 posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK);
1082 * Remove the tdb entry for this lock.
1085 delete_posix_lock_entry_by_index(fsp,entry_num);
1088 talloc_destroy(l_ctx);
1089 return ret;
1092 /****************************************************************************
1093 POSIX function to release a lock. Returns True if the
1094 lock could be released, False if not.
1095 ****************************************************************************/
1097 BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
1099 SMB_OFF_T offset;
1100 SMB_OFF_T count;
1101 BOOL ret = True;
1102 TALLOC_CTX *ul_ctx = NULL;
1103 struct lock_list *ulist = NULL;
1104 struct lock_list *ul = NULL;
1105 struct posix_lock deleted_lock;
1106 int num_overlapped_entries;
1108 DEBUG(5,("release_posix_lock: File %s, offset = %.0f, count = %.0f\n",
1109 fsp->fsp_name, (double)u_offset, (double)u_count ));
1112 * If the requested lock won't fit in the POSIX range, we will
1113 * pretend it was successful.
1116 if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
1117 return True;
1120 * We treat this as one unlock request for POSIX accounting purposes even
1121 * if it may later be split into multiple smaller POSIX unlock ranges.
1122 * num_overlapped_entries is the number of existing locks that have any
1123 * overlap with this unlock request.
1126 num_overlapped_entries = delete_posix_lock_entry(fsp, offset, count, &deleted_lock);
1128 if (num_overlapped_entries == -1) {
1129 smb_panic("release_posix_lock: unable find entry to delete !\n");
1133 * If num_overlapped_entries is > 0, and the lock_type we just deleted from the tdb was
1134 * a POSIX write lock, then before doing the unlock we need to downgrade
1135 * the POSIX lock to a read lock. This allows any overlapping read locks
1136 * to be atomically maintained.
1139 if (num_overlapped_entries > 0 && deleted_lock.lock_type == F_WRLCK) {
1140 if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_RDLCK)) {
1141 DEBUG(0,("release_posix_lock: downgrade of lock failed with error %s !\n", strerror(errno) ));
1142 return False;
1146 if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) {
1147 DEBUG(0,("release_posix_lock: unable to init talloc context.\n"));
1148 return True; /* Not a fatal error. */
1151 if ((ul = (struct lock_list *)talloc(ul_ctx, sizeof(struct lock_list))) == NULL) {
1152 DEBUG(0,("release_posix_lock: unable to talloc unlock list.\n"));
1153 talloc_destroy(ul_ctx);
1154 return True; /* Not a fatal error. */
1158 * Create the initial list entry containing the
1159 * lock we want to remove.
1162 ZERO_STRUCTP(ul);
1163 ul->start = offset;
1164 ul->size = count;
1166 DLIST_ADD(ulist, ul);
1169 * The following call calculates if there are any
1170 * overlapping locks held by this process on
1171 * fd's open on the same file and creates a
1172 * list of unlock ranges that will allow
1173 * POSIX lock ranges to remain on the file whilst the
1174 * unlocks are performed.
1177 ulist = posix_lock_list(ul_ctx, ulist, fsp);
1180 * Release the POSIX locks on the list of ranges returned.
1183 for(; ulist; ulist = ulist->next) {
1184 offset = ulist->start;
1185 count = ulist->size;
1187 DEBUG(5,("release_posix_lock: Real unlock: offset = %.0f, count = %.0f\n",
1188 (double)offset, (double)count ));
1190 if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK))
1191 ret = False;
1194 talloc_destroy(ul_ctx);
1196 return ret;
1199 /****************************************************************************
1200 Remove all lock entries for a specific dev/inode pair from the tdb.
1201 ****************************************************************************/
1203 static void delete_posix_lock_entries(files_struct *fsp)
1205 TDB_DATA kbuf = locking_key_fsp(fsp);
1207 if (tdb_delete(posix_lock_tdb, kbuf) == -1)
1208 DEBUG(0,("delete_close_entries: tdb_delete fail !\n"));
1211 /****************************************************************************
1212 Debug function.
1213 ****************************************************************************/
1215 static void dump_entry(struct posix_lock *pl)
1217 DEBUG(10,("entry: start=%.0f, size=%.0f, type=%d, fd=%i\n",
1218 (double)pl->start, (double)pl->size, (int)pl->lock_type, pl->fd ));
1221 /****************************************************************************
1222 Remove any locks on this fd. Called from file_close().
1223 ****************************************************************************/
1225 void posix_locking_close_file(files_struct *fsp)
1227 struct posix_lock *entries = NULL;
1228 size_t count, i;
1231 * Optimization for the common case where we are the only
1232 * opener of a file. If all fd entries are our own, we don't
1233 * need to explicitly release all the locks via the POSIX functions,
1234 * we can just remove all the entries in the tdb and allow the
1235 * close to remove the real locks.
1238 count = get_posix_lock_entries(fsp, &entries);
1240 if (count == 0) {
1241 DEBUG(10,("posix_locking_close_file: file %s has no outstanding locks.\n", fsp->fsp_name ));
1242 return;
1245 for (i = 0; i < count; i++) {
1246 if (entries[i].fd != fsp->fd )
1247 break;
1249 dump_entry(&entries[i]);
1252 if (i == count) {
1253 /* All locks are ours. */
1254 DEBUG(10,("posix_locking_close_file: file %s has %u outstanding locks, but all on one fd.\n",
1255 fsp->fsp_name, (unsigned int)count ));
1256 SAFE_FREE(entries);
1257 delete_posix_lock_entries(fsp);
1258 return;
1262 * Difficult case. We need to delete all our locks, whilst leaving
1263 * all other POSIX locks in place.
1266 for (i = 0; i < count; i++) {
1267 struct posix_lock *pl = &entries[i];
1268 if (pl->fd == fsp->fd)
1269 release_posix_lock(fsp, (SMB_BIG_UINT)pl->start, (SMB_BIG_UINT)pl->size );
1271 SAFE_FREE(entries);
1274 /*******************************************************************
1275 Create the in-memory POSIX lock databases.
1276 ********************************************************************/
1278 BOOL posix_locking_init(int read_only)
1280 if (posix_lock_tdb && posix_pending_close_tdb)
1281 return True;
1283 if (!posix_lock_tdb)
1284 posix_lock_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL,
1285 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
1286 if (!posix_lock_tdb) {
1287 DEBUG(0,("Failed to open POSIX byte range locking database.\n"));
1288 return False;
1290 if (!posix_pending_close_tdb)
1291 posix_pending_close_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL,
1292 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
1293 if (!posix_pending_close_tdb) {
1294 DEBUG(0,("Failed to open POSIX pending close database.\n"));
1295 return False;
1298 return True;
1301 /*******************************************************************
1302 Delete the in-memory POSIX lock databases.
1303 ********************************************************************/
1305 BOOL posix_locking_end(void)
1307 if (posix_lock_tdb && tdb_close(posix_lock_tdb) != 0)
1308 return False;
1309 if (posix_pending_close_tdb && tdb_close(posix_pending_close_tdb) != 0)
1310 return False;
1311 return True;