r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.git] / source3 / locking / posix.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Locking functions
4    Copyright (C) Jeremy Allison 1992-2006
5    
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 3 of the License, or
9    (at your option) any later version.
10    
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.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19    Revision History:
20
21    POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
22 */
23
24 #include "includes.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_LOCKING
28
29 /*
30  * The pending close database handle.
31  */
32
33 static TDB_CONTEXT *posix_pending_close_tdb;
34
35 /****************************************************************************
36  First - the functions that deal with the underlying system locks - these
37  functions are used no matter if we're mapping CIFS Windows locks or CIFS
38  POSIX locks onto POSIX.
39 ****************************************************************************/
40
41 /****************************************************************************
42  Utility function to map a lock type correctly depending on the open
43  mode of a file.
44 ****************************************************************************/
45
46 static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type)
47 {
48         if((lock_type == WRITE_LOCK) && !fsp->can_write) {
49                 /*
50                  * Many UNIX's cannot get a write lock on a file opened read-only.
51                  * Win32 locking semantics allow this.
52                  * Do the best we can and attempt a read-only lock.
53                  */
54                 DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n"));
55                 return F_RDLCK;
56         }
57
58         /*
59          * This return should be the most normal, as we attempt
60          * to always open files read/write.
61          */
62
63         return (lock_type == READ_LOCK) ? F_RDLCK : F_WRLCK;
64 }
65
66 /****************************************************************************
67  Debugging aid :-).
68 ****************************************************************************/
69
70 static const char *posix_lock_type_name(int lock_type)
71 {
72         return (lock_type == F_RDLCK) ? "READ" : "WRITE";
73 }
74
75 /****************************************************************************
76  Check to see if the given unsigned lock range is within the possible POSIX
77  range. Modifies the given args to be in range if possible, just returns
78  False if not.
79 ****************************************************************************/
80
81 static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
82                                 SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
83 {
84         SMB_OFF_T offset = (SMB_OFF_T)u_offset;
85         SMB_OFF_T count = (SMB_OFF_T)u_count;
86
87         /*
88          * For the type of system we are, attempt to
89          * find the maximum positive lock offset as an SMB_OFF_T.
90          */
91
92 #if defined(MAX_POSITIVE_LOCK_OFFSET) /* Some systems have arbitrary limits. */
93
94         SMB_OFF_T max_positive_lock_offset = (MAX_POSITIVE_LOCK_OFFSET);
95
96 #elif defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
97
98         /*
99          * In this case SMB_OFF_T is 64 bits,
100          * and the underlying system can handle 64 bit signed locks.
101          */
102
103         SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4);
104         SMB_OFF_T mask = (mask2<<1);
105         SMB_OFF_T max_positive_lock_offset = ~mask;
106
107 #else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
108
109         /*
110          * In this case either SMB_OFF_T is 32 bits,
111          * or the underlying system cannot handle 64 bit signed locks.
112          * All offsets & counts must be 2^31 or less.
113          */
114
115         SMB_OFF_T max_positive_lock_offset = 0x7FFFFFFF;
116
117 #endif /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
118
119         /*
120          * POSIX locks of length zero mean lock to end-of-file.
121          * Win32 locks of length zero are point probes. Ignore
122          * any Win32 locks of length zero. JRA.
123          */
124
125         if (count == (SMB_OFF_T)0) {
126                 DEBUG(10,("posix_lock_in_range: count = 0, ignoring.\n"));
127                 return False;
128         }
129
130         /*
131          * If the given offset was > max_positive_lock_offset then we cannot map this at all
132          * ignore this lock.
133          */
134
135         if (u_offset & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
136                 DEBUG(10,("posix_lock_in_range: (offset = %.0f) offset > %.0f and we cannot handle this. Ignoring lock.\n",
137                                 (double)u_offset, (double)((SMB_BIG_UINT)max_positive_lock_offset) ));
138                 return False;
139         }
140
141         /*
142          * We must truncate the count to less than max_positive_lock_offset.
143          */
144
145         if (u_count & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
146                 count = max_positive_lock_offset;
147         }
148
149         /*
150          * Truncate count to end at max lock offset.
151          */
152
153         if (offset + count < 0 || offset + count > max_positive_lock_offset) {
154                 count = max_positive_lock_offset - offset;
155         }
156
157         /*
158          * If we ate all the count, ignore this lock.
159          */
160
161         if (count == 0) {
162                 DEBUG(10,("posix_lock_in_range: Count = 0. Ignoring lock u_offset = %.0f, u_count = %.0f\n",
163                                 (double)u_offset, (double)u_count ));
164                 return False;
165         }
166
167         /*
168          * The mapping was successful.
169          */
170
171         DEBUG(10,("posix_lock_in_range: offset_out = %.0f, count_out = %.0f\n",
172                         (double)offset, (double)count ));
173
174         *offset_out = offset;
175         *count_out = count;
176         
177         return True;
178 }
179
180 /****************************************************************************
181  Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and
182  broken NFS implementations.
183 ****************************************************************************/
184
185 static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
186 {
187         BOOL ret;
188
189         DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fh->fd,op,(double)offset,(double)count,type));
190
191         ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
192
193         if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno ==  EINVAL))) {
194
195                 DEBUG(0,("posix_fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n",
196                                         (double)offset,(double)count));
197                 DEBUGADD(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
198                 DEBUGADD(0,("on 32 bit NFS mounted file systems.\n"));
199
200                 /*
201                  * If the offset is > 0x7FFFFFFF then this will cause problems on
202                  * 32 bit NFS mounted filesystems. Just ignore it.
203                  */
204
205                 if (offset & ~((SMB_OFF_T)0x7fffffff)) {
206                         DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
207                         return True;
208                 }
209
210                 if (count & ~((SMB_OFF_T)0x7fffffff)) {
211                         /* 32 bit NFS file system, retry with smaller offset */
212                         DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
213                         errno = 0;
214                         count &= 0x7fffffff;
215                         ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
216                 }
217         }
218
219         DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
220         return ret;
221 }
222
223 /****************************************************************************
224  Actual function that gets POSIX locks. Copes with 64 -> 32 bit cruft and
225  broken NFS implementations.
226 ****************************************************************************/
227
228 static BOOL posix_fcntl_getlock(files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype)
229 {
230         pid_t pid;
231         BOOL ret;
232
233         DEBUG(8,("posix_fcntl_getlock %d %.0f %.0f %d\n",
234                 fsp->fh->fd,(double)*poffset,(double)*pcount,*ptype));
235
236         ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
237
238         if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno ==  EINVAL))) {
239
240                 DEBUG(0,("posix_fcntl_getlock: WARNING: lock request at offset %.0f, length %.0f returned\n",
241                                         (double)*poffset,(double)*pcount));
242                 DEBUGADD(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
243                 DEBUGADD(0,("on 32 bit NFS mounted file systems.\n"));
244
245                 /*
246                  * If the offset is > 0x7FFFFFFF then this will cause problems on
247                  * 32 bit NFS mounted filesystems. Just ignore it.
248                  */
249
250                 if (*poffset & ~((SMB_OFF_T)0x7fffffff)) {
251                         DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
252                         return True;
253                 }
254
255                 if (*pcount & ~((SMB_OFF_T)0x7fffffff)) {
256                         /* 32 bit NFS file system, retry with smaller offset */
257                         DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
258                         errno = 0;
259                         *pcount &= 0x7fffffff;
260                         ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
261                 }
262         }
263
264         DEBUG(8,("posix_fcntl_getlock: Lock query call %s\n", ret ? "successful" : "failed"));
265         return ret;
266 }
267
268 /****************************************************************************
269  POSIX function to see if a file region is locked. Returns True if the
270  region is locked, False otherwise.
271 ****************************************************************************/
272
273 BOOL is_posix_locked(files_struct *fsp,
274                         SMB_BIG_UINT *pu_offset,
275                         SMB_BIG_UINT *pu_count,
276                         enum brl_type *plock_type,
277                         enum brl_flavour lock_flav)
278 {
279         SMB_OFF_T offset;
280         SMB_OFF_T count;
281         int posix_lock_type = map_posix_lock_type(fsp,*plock_type);
282
283         DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
284                 fsp->fsp_name, (double)*pu_offset, (double)*pu_count, posix_lock_type_name(*plock_type) ));
285
286         /*
287          * If the requested lock won't fit in the POSIX range, we will
288          * never set it, so presume it is not locked.
289          */
290
291         if(!posix_lock_in_range(&offset, &count, *pu_offset, *pu_count)) {
292                 return False;
293         }
294
295         if (!posix_fcntl_getlock(fsp,&offset,&count,&posix_lock_type)) {
296                 return False;
297         }
298
299         if (posix_lock_type == F_UNLCK) {
300                 return False;
301         }
302
303         if (lock_flav == POSIX_LOCK) {
304                 /* Only POSIX lock queries need to know the details. */
305                 *pu_offset = (SMB_BIG_UINT)offset;
306                 *pu_count = (SMB_BIG_UINT)count;
307                 *plock_type = (posix_lock_type == F_RDLCK) ? READ_LOCK : WRITE_LOCK;
308         }
309         return True;
310 }
311
312 /****************************************************************************
313  Next - the functions that deal with in memory database storing representations
314  of either Windows CIFS locks or POSIX CIFS locks.
315 ****************************************************************************/
316
317 /* The key used in the in-memory POSIX databases. */
318
319 struct lock_ref_count_key {
320         struct file_id id;
321         char r;
322 }; 
323
324 /*******************************************************************
325  Form a static locking key for a dev/inode pair for the fd array.
326 ******************************************************************/
327
328 static TDB_DATA fd_array_key(struct file_id id)
329 {
330         static struct file_id key;
331         TDB_DATA kbuf;
332         key = id;
333         kbuf.dptr = (uint8 *)&key;
334         kbuf.dsize = sizeof(key);
335         return kbuf;
336 }
337
338 /*******************************************************************
339  Form a static locking key for a dev/inode pair for the lock ref count
340 ******************************************************************/
341
342 static TDB_DATA locking_ref_count_key(struct file_id id)
343 {
344         static struct lock_ref_count_key key;
345         TDB_DATA kbuf;
346
347         memset(&key, '\0', sizeof(key));
348         key.id = id;
349         key.r = 'r';
350         kbuf.dptr = (uint8 *)&key;
351         kbuf.dsize = sizeof(key);
352         return kbuf;
353 }
354
355 /*******************************************************************
356  Convenience function to get an fd_array key from an fsp.
357 ******************************************************************/
358
359 static TDB_DATA fd_array_key_fsp(files_struct *fsp)
360 {
361         return fd_array_key(fsp->file_id);
362 }
363
364 /*******************************************************************
365  Convenience function to get a lock ref count key from an fsp.
366 ******************************************************************/
367
368 static TDB_DATA locking_ref_count_key_fsp(files_struct *fsp)
369 {
370         return locking_ref_count_key(fsp->file_id);
371 }
372
373 /*******************************************************************
374  Create the in-memory POSIX lock databases.
375 ********************************************************************/
376
377 BOOL posix_locking_init(int read_only)
378 {
379         if (posix_pending_close_tdb) {
380                 return True;
381         }
382         
383         if (!posix_pending_close_tdb) {
384                 posix_pending_close_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL,
385                                                    read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
386         }
387         if (!posix_pending_close_tdb) {
388                 DEBUG(0,("Failed to open POSIX pending close database.\n"));
389                 return False;
390         }
391
392         return True;
393 }
394
395 /*******************************************************************
396  Delete the in-memory POSIX lock databases.
397 ********************************************************************/
398
399 BOOL posix_locking_end(void)
400 {
401         if (posix_pending_close_tdb && tdb_close(posix_pending_close_tdb) != 0) {
402                 return False;
403         }
404         return True;
405 }
406
407 /****************************************************************************
408  Next - the functions that deal with storing fd's that have outstanding
409  POSIX locks when closed.
410 ****************************************************************************/
411
412 /****************************************************************************
413  The records in posix_pending_close_tdb are composed of an array of ints
414  keyed by dev/ino pair.
415  The first int is a reference count of the number of outstanding locks on
416  all open fd's on this dev/ino pair. Any subsequent ints are the fd's that
417  were open on this dev/ino pair that should have been closed, but can't as
418  the lock ref count is non zero.
419 ****************************************************************************/
420
421 /****************************************************************************
422  Keep a reference count of the number of Windows locks open on this dev/ino
423  pair. Creates entry if it doesn't exist.
424 ****************************************************************************/
425
426 static void increment_windows_lock_ref_count(files_struct *fsp)
427 {
428         TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
429         TDB_DATA dbuf;
430         int lock_ref_count;
431
432         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
433         if (dbuf.dptr == NULL) {
434                 dbuf.dptr = (uint8 *)SMB_MALLOC_P(int);
435                 if (!dbuf.dptr) {
436                         smb_panic("increment_windows_lock_ref_count: malloc fail");
437                 }
438                 memset(dbuf.dptr, '\0', sizeof(int));
439                 dbuf.dsize = sizeof(int);
440         }
441
442         memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
443         lock_ref_count++;
444         memcpy(dbuf.dptr, &lock_ref_count, sizeof(int));
445         
446         if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
447                 smb_panic("increment_windows_lock_ref_count: tdb_store_fail");
448         }
449         SAFE_FREE(dbuf.dptr);
450
451         DEBUG(10,("increment_windows_lock_ref_count for file now %s = %d\n",
452                 fsp->fsp_name, lock_ref_count ));
453 }
454
455 static void decrement_windows_lock_ref_count(files_struct *fsp)
456 {
457         TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
458         TDB_DATA dbuf;
459         int lock_ref_count;
460
461         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
462         if (!dbuf.dptr) {
463                 smb_panic("decrement_windows_lock_ref_count: logic error");
464         }
465
466         memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
467         lock_ref_count--;
468         memcpy(dbuf.dptr, &lock_ref_count, sizeof(int));
469
470         if (lock_ref_count < 0) {
471                 smb_panic("decrement_windows_lock_ref_count: lock_count logic error");
472         }
473
474         if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
475                 smb_panic("decrement_windows_lock_ref_count: tdb_store_fail");
476         }
477         SAFE_FREE(dbuf.dptr);
478
479         DEBUG(10,("decrement_windows_lock_ref_count for file now %s = %d\n",
480                 fsp->fsp_name, lock_ref_count ));
481 }
482
483 /****************************************************************************
484  Bulk delete - subtract as many locks as we've just deleted.
485 ****************************************************************************/
486
487 void reduce_windows_lock_ref_count(files_struct *fsp, unsigned int dcount)
488 {
489         TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
490         TDB_DATA dbuf;
491         int lock_ref_count;
492
493         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
494         if (!dbuf.dptr) {
495                 return;
496         }
497
498         memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
499         lock_ref_count -= dcount;
500
501         if (lock_ref_count < 0) {
502                 smb_panic("reduce_windows_lock_ref_count: lock_count logic error");
503         }
504         memcpy(dbuf.dptr, &lock_ref_count, sizeof(int));
505         
506         if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
507                 smb_panic("reduce_windows_lock_ref_count: tdb_store_fail");
508         }
509         SAFE_FREE(dbuf.dptr);
510
511         DEBUG(10,("reduce_windows_lock_ref_count for file now %s = %d\n",
512                 fsp->fsp_name, lock_ref_count ));
513 }
514
515 /****************************************************************************
516  Fetch the lock ref count.
517 ****************************************************************************/
518
519 static int get_windows_lock_ref_count(files_struct *fsp)
520 {
521         TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
522         TDB_DATA dbuf;
523         int lock_ref_count;
524
525         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
526         if (!dbuf.dptr) {
527                 lock_ref_count = 0;
528         } else {
529                 memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
530         }
531         SAFE_FREE(dbuf.dptr);
532
533         DEBUG(10,("get_windows_lock_count for file %s = %d\n",
534                 fsp->fsp_name, lock_ref_count ));
535         return lock_ref_count;
536 }
537
538 /****************************************************************************
539  Delete a lock_ref_count entry.
540 ****************************************************************************/
541
542 static void delete_windows_lock_ref_count(files_struct *fsp)
543 {
544         TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
545
546         /* Not a bug if it doesn't exist - no locks were ever granted. */
547         tdb_delete(posix_pending_close_tdb, kbuf);
548         DEBUG(10,("delete_windows_lock_ref_count for file %s\n", fsp->fsp_name));
549 }
550
551 /****************************************************************************
552  Add an fd to the pending close tdb.
553 ****************************************************************************/
554
555 static void add_fd_to_close_entry(files_struct *fsp)
556 {
557         TDB_DATA kbuf = fd_array_key_fsp(fsp);
558         TDB_DATA dbuf;
559
560         dbuf.dptr = NULL;
561         dbuf.dsize = 0;
562
563         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
564
565         dbuf.dptr = (uint8 *)SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(int));
566         if (!dbuf.dptr) {
567                 smb_panic("add_fd_to_close_entry: SMB_REALLOC failed");
568         }
569
570         memcpy(dbuf.dptr + dbuf.dsize, &fsp->fh->fd, sizeof(int));
571         dbuf.dsize += sizeof(int);
572
573         if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
574                 smb_panic("add_fd_to_close_entry: tdb_store_fail");
575         }
576
577         DEBUG(10,("add_fd_to_close_entry: added fd %d file %s\n",
578                 fsp->fh->fd, fsp->fsp_name ));
579
580         SAFE_FREE(dbuf.dptr);
581 }
582
583 /****************************************************************************
584  Remove all fd entries for a specific dev/inode pair from the tdb.
585 ****************************************************************************/
586
587 static void delete_close_entries(files_struct *fsp)
588 {
589         TDB_DATA kbuf = fd_array_key_fsp(fsp);
590
591         if (tdb_delete(posix_pending_close_tdb, kbuf) == -1) {
592                 smb_panic("delete_close_entries: tdb_delete failed");
593         }
594 }
595
596 /****************************************************************************
597  Get the array of POSIX pending close records for an open fsp. Caller must
598  free. Returns number of entries.
599 ****************************************************************************/
600
601 static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries)
602 {
603         TDB_DATA kbuf = fd_array_key_fsp(fsp);
604         TDB_DATA dbuf;
605         size_t count = 0;
606
607         *entries = NULL;
608         dbuf.dptr = NULL;
609
610         dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
611
612         if (!dbuf.dptr) {
613                 return 0;
614         }
615
616         *entries = (int *)dbuf.dptr;
617         count = (size_t)(dbuf.dsize / sizeof(int));
618
619         return count;
620 }
621
622 /****************************************************************************
623  Deal with pending closes needed by POSIX locking support.
624  Note that posix_locking_close_file() is expected to have been called
625  to delete all locks on this fsp before this function is called.
626 ****************************************************************************/
627
628 NTSTATUS fd_close_posix(struct connection_struct *conn, files_struct *fsp)
629 {
630         int saved_errno = 0;
631         int ret;
632         int *fd_array = NULL;
633         size_t count, i;
634
635         if (!lp_locking(fsp->conn->params) || !lp_posix_locking(conn->params)) {
636                 /*
637                  * No locking or POSIX to worry about or we want POSIX semantics
638                  * which will lose all locks on all fd's open on this dev/inode,
639                  * just close.
640                  */
641                 ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd);
642                 fsp->fh->fd = -1;
643                 return map_nt_error_from_unix(errno);
644         }
645
646         if (get_windows_lock_ref_count(fsp)) {
647
648                 /*
649                  * There are outstanding locks on this dev/inode pair on other fds.
650                  * Add our fd to the pending close tdb and set fsp->fh->fd to -1.
651                  */
652
653                 add_fd_to_close_entry(fsp);
654                 fsp->fh->fd = -1;
655                 return NT_STATUS_OK;
656         }
657
658         /*
659          * No outstanding locks. Get the pending close fd's
660          * from the tdb and close them all.
661          */
662
663         count = get_posix_pending_close_entries(fsp, &fd_array);
664
665         if (count) {
666                 DEBUG(10,("fd_close_posix: doing close on %u fd's.\n", (unsigned int)count ));
667
668                 for(i = 0; i < count; i++) {
669                         if (SMB_VFS_CLOSE(fsp,fd_array[i]) == -1) {
670                                 saved_errno = errno;
671                         }
672                 }
673
674                 /*
675                  * Delete all fd's stored in the tdb
676                  * for this dev/inode pair.
677                  */
678
679                 delete_close_entries(fsp);
680         }
681
682         SAFE_FREE(fd_array);
683
684         /* Don't need a lock ref count on this dev/ino anymore. */
685         delete_windows_lock_ref_count(fsp);
686
687         /*
688          * Finally close the fd associated with this fsp.
689          */
690
691         ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd);
692
693         if (ret == 0 && saved_errno != 0) {
694                 errno = saved_errno;
695                 ret = -1;
696         } 
697
698         fsp->fh->fd = -1;
699
700         if (ret == -1) {
701                 return map_nt_error_from_unix(errno);
702         }
703
704         return NT_STATUS_OK;
705 }
706
707 /****************************************************************************
708  Next - the functions that deal with the mapping CIFS Windows locks onto
709  the underlying system POSIX locks.
710 ****************************************************************************/
711
712 /*
713  * Structure used when splitting a lock range
714  * into a POSIX lock range. Doubly linked list.
715  */
716
717 struct lock_list {
718         struct lock_list *next;
719         struct lock_list *prev;
720         SMB_OFF_T start;
721         SMB_OFF_T size;
722 };
723
724 /****************************************************************************
725  Create a list of lock ranges that don't overlap a given range. Used in calculating
726  POSIX locks and unlocks. This is a difficult function that requires ASCII art to
727  understand it :-).
728 ****************************************************************************/
729
730 static struct lock_list *posix_lock_list(TALLOC_CTX *ctx,
731                                                 struct lock_list *lhead,
732                                                 const struct lock_context *lock_ctx, /* Lock context lhead belongs to. */
733                                                 files_struct *fsp,
734                                                 const struct lock_struct *plocks,
735                                                 int num_locks)
736 {
737         int i;
738
739         /*
740          * Check the current lock list on this dev/inode pair.
741          * Quit if the list is deleted.
742          */
743
744         DEBUG(10,("posix_lock_list: curr: start=%.0f,size=%.0f\n",
745                 (double)lhead->start, (double)lhead->size ));
746
747         for (i=0; i<num_locks && lhead; i++) {
748                 const struct lock_struct *lock = &plocks[i];
749                 struct lock_list *l_curr;
750
751                 /* Ignore all but read/write locks. */
752                 if (lock->lock_type != READ_LOCK && lock->lock_type != WRITE_LOCK) {
753                         continue;
754                 }
755
756                 /* Ignore locks not owned by this process. */
757                 if (!procid_equal(&lock->context.pid, &lock_ctx->pid)) {
758                         continue;
759                 }
760
761                 /*
762                  * Walk the lock list, checking for overlaps. Note that
763                  * the lock list can expand within this loop if the current
764                  * range being examined needs to be split.
765                  */
766
767                 for (l_curr = lhead; l_curr;) {
768
769                         DEBUG(10,("posix_lock_list: lock: fnum=%d: start=%.0f,size=%.0f:type=%s", lock->fnum,
770                                 (double)lock->start, (double)lock->size, posix_lock_type_name(lock->lock_type) ));
771
772                         if ( (l_curr->start >= (lock->start + lock->size)) ||
773                                  (lock->start >= (l_curr->start + l_curr->size))) {
774
775                                 /* No overlap with existing lock - leave this range alone. */
776 /*********************************************
777                                              +---------+
778                                              | l_curr  |
779                                              +---------+
780                                 +-------+
781                                 | lock  |
782                                 +-------+
783 OR....
784              +---------+
785              |  l_curr |
786              +---------+
787 **********************************************/
788
789                                 DEBUG(10,(" no overlap case.\n" ));
790
791                                 l_curr = l_curr->next;
792
793                         } else if ( (l_curr->start >= lock->start) &&
794                                                 (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
795
796                                 /*
797                                  * This range is completely overlapped by this existing lock range
798                                  * and thus should have no effect. Delete it from the list.
799                                  */
800 /*********************************************
801                 +---------+
802                 |  l_curr |
803                 +---------+
804         +---------------------------+
805         |       lock                |
806         +---------------------------+
807 **********************************************/
808                                 /* Save the next pointer */
809                                 struct lock_list *ul_next = l_curr->next;
810
811                                 DEBUG(10,(" delete case.\n" ));
812
813                                 DLIST_REMOVE(lhead, l_curr);
814                                 if(lhead == NULL) {
815                                         break; /* No more list... */
816                                 }
817
818                                 l_curr = ul_next;
819                                 
820                         } else if ( (l_curr->start >= lock->start) &&
821                                                 (l_curr->start < lock->start + lock->size) &&
822                                                 (l_curr->start + l_curr->size > lock->start + lock->size) ) {
823
824                                 /*
825                                  * This range overlaps the existing lock range at the high end.
826                                  * Truncate by moving start to existing range end and reducing size.
827                                  */
828 /*********************************************
829                 +---------------+
830                 |  l_curr       |
831                 +---------------+
832         +---------------+
833         |    lock       |
834         +---------------+
835 BECOMES....
836                         +-------+
837                         | l_curr|
838                         +-------+
839 **********************************************/
840
841                                 l_curr->size = (l_curr->start + l_curr->size) - (lock->start + lock->size);
842                                 l_curr->start = lock->start + lock->size;
843
844                                 DEBUG(10,(" truncate high case: start=%.0f,size=%.0f\n",
845                                                                 (double)l_curr->start, (double)l_curr->size ));
846
847                                 l_curr = l_curr->next;
848
849                         } else if ( (l_curr->start < lock->start) &&
850                                                 (l_curr->start + l_curr->size > lock->start) &&
851                                                 (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
852
853                                 /*
854                                  * This range overlaps the existing lock range at the low end.
855                                  * Truncate by reducing size.
856                                  */
857 /*********************************************
858    +---------------+
859    |  l_curr       |
860    +---------------+
861            +---------------+
862            |    lock       |
863            +---------------+
864 BECOMES....
865    +-------+
866    | l_curr|
867    +-------+
868 **********************************************/
869
870                                 l_curr->size = lock->start - l_curr->start;
871
872                                 DEBUG(10,(" truncate low case: start=%.0f,size=%.0f\n",
873                                                                 (double)l_curr->start, (double)l_curr->size ));
874
875                                 l_curr = l_curr->next;
876                 
877                         } else if ( (l_curr->start < lock->start) &&
878                                                 (l_curr->start + l_curr->size > lock->start + lock->size) ) {
879                                 /*
880                                  * Worst case scenario. Range completely overlaps an existing
881                                  * lock range. Split the request into two, push the new (upper) request
882                                  * into the dlink list, and continue with the entry after l_new (as we
883                                  * know that l_new will not overlap with this lock).
884                                  */
885 /*********************************************
886         +---------------------------+
887         |        l_curr             |
888         +---------------------------+
889                 +---------+
890                 | lock    |
891                 +---------+
892 BECOMES.....
893         +-------+         +---------+
894         | l_curr|         | l_new   |
895         +-------+         +---------+
896 **********************************************/
897                                 struct lock_list *l_new = TALLOC_P(ctx, struct lock_list);
898
899                                 if(l_new == NULL) {
900                                         DEBUG(0,("posix_lock_list: talloc fail.\n"));
901                                         return NULL; /* The talloc_destroy takes care of cleanup. */
902                                 }
903
904                                 ZERO_STRUCTP(l_new);
905                                 l_new->start = lock->start + lock->size;
906                                 l_new->size = l_curr->start + l_curr->size - l_new->start;
907
908                                 /* Truncate the l_curr. */
909                                 l_curr->size = lock->start - l_curr->start;
910
911                                 DEBUG(10,(" split case: curr: start=%.0f,size=%.0f \
912 new: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size,
913                                                                 (double)l_new->start, (double)l_new->size ));
914
915                                 /*
916                                  * Add into the dlink list after the l_curr point - NOT at lhead. 
917                                  * Note we can't use DLINK_ADD here as this inserts at the head of the given list.
918                                  */
919
920                                 l_new->prev = l_curr;
921                                 l_new->next = l_curr->next;
922                                 l_curr->next = l_new;
923
924                                 /* And move after the link we added. */
925                                 l_curr = l_new->next;
926
927                         } else {
928
929                                 /*
930                                  * This logic case should never happen. Ensure this is the
931                                  * case by forcing an abort.... Remove in production.
932                                  */
933                                 pstring msg;
934
935                                 slprintf(msg, sizeof(msg)-1, "logic flaw in cases: l_curr: start = %.0f, size = %.0f : \
936 lock: start = %.0f, size = %.0f", (double)l_curr->start, (double)l_curr->size, (double)lock->start, (double)lock->size );
937
938                                 smb_panic(msg);
939                         }
940                 } /* end for ( l_curr = lhead; l_curr;) */
941         } /* end for (i=0; i<num_locks && ul_head; i++) */
942
943         return lhead;
944 }
945
946 /****************************************************************************
947  POSIX function to acquire a lock. Returns True if the
948  lock could be granted, False if not.
949 ****************************************************************************/
950
951 BOOL set_posix_lock_windows_flavour(files_struct *fsp,
952                         SMB_BIG_UINT u_offset,
953                         SMB_BIG_UINT u_count,
954                         enum brl_type lock_type,
955                         const struct lock_context *lock_ctx,
956                         const struct lock_struct *plocks,
957                         int num_locks,
958                         int *errno_ret)
959 {
960         SMB_OFF_T offset;
961         SMB_OFF_T count;
962         int posix_lock_type = map_posix_lock_type(fsp,lock_type);
963         BOOL ret = True;
964         size_t lock_count;
965         TALLOC_CTX *l_ctx = NULL;
966         struct lock_list *llist = NULL;
967         struct lock_list *ll = NULL;
968
969         DEBUG(5,("set_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n",
970                         fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
971
972         /*
973          * If the requested lock won't fit in the POSIX range, we will
974          * pretend it was successful.
975          */
976
977         if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
978                 increment_windows_lock_ref_count(fsp);
979                 return True;
980         }
981
982         /*
983          * Windows is very strange. It allows read locks to be overlayed
984          * (even over a write lock), but leaves the write lock in force until the first
985          * unlock. It also reference counts the locks. This means the following sequence :
986          *
987          * process1                                      process2
988          * ------------------------------------------------------------------------
989          * WRITE LOCK : start = 2, len = 10
990          *                                            READ LOCK: start =0, len = 10 - FAIL
991          * READ LOCK : start = 0, len = 14 
992          *                                            READ LOCK: start =0, len = 10 - FAIL
993          * UNLOCK : start = 2, len = 10
994          *                                            READ LOCK: start =0, len = 10 - OK
995          *
996          * Under POSIX, the same sequence in steps 1 and 2 would not be reference counted, but
997          * would leave a single read lock over the 0-14 region.
998          */
999         
1000         if ((l_ctx = talloc_init("set_posix_lock")) == NULL) {
1001                 DEBUG(0,("set_posix_lock_windows_flavour: unable to init talloc context.\n"));
1002                 return False;
1003         }
1004
1005         if ((ll = TALLOC_P(l_ctx, struct lock_list)) == NULL) {
1006                 DEBUG(0,("set_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
1007                 talloc_destroy(l_ctx);
1008                 return False;
1009         }
1010
1011         /*
1012          * Create the initial list entry containing the
1013          * lock we want to add.
1014          */
1015
1016         ZERO_STRUCTP(ll);
1017         ll->start = offset;
1018         ll->size = count;
1019
1020         DLIST_ADD(llist, ll);
1021
1022         /*
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.
1028          */
1029
1030         llist = posix_lock_list(l_ctx,
1031                                 llist,
1032                                 lock_ctx, /* Lock context llist belongs to. */
1033                                 fsp,
1034                                 plocks,
1035                                 num_locks);
1036
1037         /*
1038          * Add the POSIX locks on the list of ranges returned.
1039          * As the lock is supposed to be added atomically, we need to
1040          * back out all the locks if any one of these calls fail.
1041          */
1042
1043         for (lock_count = 0, ll = llist; ll; ll = ll->next, lock_count++) {
1044                 offset = ll->start;
1045                 count = ll->size;
1046
1047                 DEBUG(5,("set_posix_lock_windows_flavour: Real lock: Type = %s: offset = %.0f, count = %.0f\n",
1048                         posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
1049
1050                 if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) {
1051                         *errno_ret = errno;
1052                         DEBUG(5,("set_posix_lock_windows_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
1053                                 posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
1054                         ret = False;
1055                         break;
1056                 }
1057         }
1058
1059         if (!ret) {
1060
1061                 /*
1062                  * Back out all the POSIX locks we have on fail.
1063                  */
1064
1065                 for (ll = llist; lock_count; ll = ll->next, lock_count--) {
1066                         offset = ll->start;
1067                         count = ll->size;
1068
1069                         DEBUG(5,("set_posix_lock_windows_flavour: Backing out locks: Type = %s: offset = %.0f, count = %.0f\n",
1070                                 posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
1071
1072                         posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK);
1073                 }
1074         } else {
1075                 /* Remember the number of Windows locks we have on this dev/ino pair. */
1076                 increment_windows_lock_ref_count(fsp);
1077         }
1078
1079         talloc_destroy(l_ctx);
1080         return ret;
1081 }
1082
1083 /****************************************************************************
1084  POSIX function to release a lock. Returns True if the
1085  lock could be released, False if not.
1086 ****************************************************************************/
1087
1088 BOOL release_posix_lock_windows_flavour(files_struct *fsp,
1089                                 SMB_BIG_UINT u_offset,
1090                                 SMB_BIG_UINT u_count,
1091                                 enum brl_type deleted_lock_type,
1092                                 const struct lock_context *lock_ctx,
1093                                 const struct lock_struct *plocks,
1094                                 int num_locks)
1095 {
1096         SMB_OFF_T offset;
1097         SMB_OFF_T count;
1098         BOOL ret = True;
1099         TALLOC_CTX *ul_ctx = NULL;
1100         struct lock_list *ulist = NULL;
1101         struct lock_list *ul = NULL;
1102
1103         DEBUG(5,("release_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f\n",
1104                 fsp->fsp_name, (double)u_offset, (double)u_count ));
1105
1106         /* Remember the number of Windows locks we have on this dev/ino pair. */
1107         decrement_windows_lock_ref_count(fsp);
1108
1109         /*
1110          * If the requested lock won't fit in the POSIX range, we will
1111          * pretend it was successful.
1112          */
1113
1114         if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
1115                 return True;
1116         }
1117
1118         if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) {
1119                 DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n"));
1120                 return False;
1121         }
1122
1123         if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) {
1124                 DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
1125                 talloc_destroy(ul_ctx);
1126                 return False;
1127         }
1128
1129         /*
1130          * Create the initial list entry containing the
1131          * lock we want to remove.
1132          */
1133
1134         ZERO_STRUCTP(ul);
1135         ul->start = offset;
1136         ul->size = count;
1137
1138         DLIST_ADD(ulist, ul);
1139
1140         /*
1141          * The following call calculates if there are any
1142          * overlapping locks held by this process on
1143          * fd's open on the same file and creates a
1144          * list of unlock ranges that will allow
1145          * POSIX lock ranges to remain on the file whilst the
1146          * unlocks are performed.
1147          */
1148
1149         ulist = posix_lock_list(ul_ctx,
1150                                 ulist,
1151                                 lock_ctx, /* Lock context ulist belongs to. */
1152                                 fsp,
1153                                 plocks,
1154                                 num_locks);
1155
1156         /*
1157          * If there were any overlapped entries (list is > 1 or size or start have changed),
1158          * and the lock_type we just deleted from
1159          * the upper layer tdb was a write lock, then before doing the unlock we need to downgrade
1160          * the POSIX lock to a read lock. This allows any overlapping read locks
1161          * to be atomically maintained.
1162          */
1163
1164         if (deleted_lock_type == WRITE_LOCK &&
1165                         (!ulist || ulist->next != NULL || ulist->start != offset || ulist->size != count)) {
1166
1167                 DEBUG(5,("release_posix_lock_windows_flavour: downgrading lock to READ: offset = %.0f, count = %.0f\n",
1168                         (double)offset, (double)count ));
1169
1170                 if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_RDLCK)) {
1171                         DEBUG(0,("release_posix_lock_windows_flavour: downgrade of lock failed with error %s !\n", strerror(errno) ));
1172                         talloc_destroy(ul_ctx);
1173                         return False;
1174                 }
1175         }
1176
1177         /*
1178          * Release the POSIX locks on the list of ranges returned.
1179          */
1180
1181         for(; ulist; ulist = ulist->next) {
1182                 offset = ulist->start;
1183                 count = ulist->size;
1184
1185                 DEBUG(5,("release_posix_lock_windows_flavour: Real unlock: offset = %.0f, count = %.0f\n",
1186                         (double)offset, (double)count ));
1187
1188                 if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) {
1189                         ret = False;
1190                 }
1191         }
1192
1193         talloc_destroy(ul_ctx);
1194         return ret;
1195 }
1196
1197 /****************************************************************************
1198  Next - the functions that deal with mapping CIFS POSIX locks onto
1199  the underlying system POSIX locks.
1200 ****************************************************************************/
1201
1202 /****************************************************************************
1203  POSIX function to acquire a lock. Returns True if the
1204  lock could be granted, False if not.
1205  As POSIX locks don't stack or conflict (they just overwrite)
1206  we can map the requested lock directly onto a system one. We
1207  know it doesn't conflict with locks on other contexts as the
1208  upper layer would have refused it.
1209 ****************************************************************************/
1210
1211 BOOL set_posix_lock_posix_flavour(files_struct *fsp,
1212                         SMB_BIG_UINT u_offset,
1213                         SMB_BIG_UINT u_count,
1214                         enum brl_type lock_type,
1215                         int *errno_ret)
1216 {
1217         SMB_OFF_T offset;
1218         SMB_OFF_T count;
1219         int posix_lock_type = map_posix_lock_type(fsp,lock_type);
1220
1221         DEBUG(5,("set_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n",
1222                         fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
1223
1224         /*
1225          * If the requested lock won't fit in the POSIX range, we will
1226          * pretend it was successful.
1227          */
1228
1229         if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
1230                 return True;
1231         }
1232
1233         if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) {
1234                 *errno_ret = errno;
1235                 DEBUG(5,("set_posix_lock_posix_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
1236                         posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
1237                 return False;
1238         }
1239         return True;
1240 }
1241
1242 /****************************************************************************
1243  POSIX function to release a lock. Returns True if the
1244  lock could be released, False if not.
1245  We are given a complete lock state from the upper layer which is what the lock
1246  state should be after the unlock has already been done, so what
1247  we do is punch out holes in the unlock range where locks owned by this process
1248  have a different lock context.
1249 ****************************************************************************/
1250
1251 BOOL release_posix_lock_posix_flavour(files_struct *fsp,
1252                                 SMB_BIG_UINT u_offset,
1253                                 SMB_BIG_UINT u_count,
1254                                 const struct lock_context *lock_ctx,
1255                                 const struct lock_struct *plocks,
1256                                 int num_locks)
1257 {
1258         BOOL ret = True;
1259         SMB_OFF_T offset;
1260         SMB_OFF_T count;
1261         TALLOC_CTX *ul_ctx = NULL;
1262         struct lock_list *ulist = NULL;
1263         struct lock_list *ul = NULL;
1264
1265         DEBUG(5,("release_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f\n",
1266                 fsp->fsp_name, (double)u_offset, (double)u_count ));
1267
1268         /*
1269          * If the requested lock won't fit in the POSIX range, we will
1270          * pretend it was successful.
1271          */
1272
1273         if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
1274                 return True;
1275         }
1276
1277         if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) {
1278                 DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n"));
1279                 return False;
1280         }
1281
1282         if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) {
1283                 DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
1284                 talloc_destroy(ul_ctx);
1285                 return False;
1286         }
1287
1288         /*
1289          * Create the initial list entry containing the
1290          * lock we want to remove.
1291          */
1292
1293         ZERO_STRUCTP(ul);
1294         ul->start = offset;
1295         ul->size = count;
1296
1297         DLIST_ADD(ulist, ul);
1298
1299         /*
1300          * Walk the given array creating a linked list
1301          * of unlock requests.
1302          */
1303
1304         ulist = posix_lock_list(ul_ctx,
1305                                 ulist,
1306                                 lock_ctx, /* Lock context ulist belongs to. */
1307                                 fsp,
1308                                 plocks,
1309                                 num_locks);
1310
1311         /*
1312          * Release the POSIX locks on the list of ranges returned.
1313          */
1314
1315         for(; ulist; ulist = ulist->next) {
1316                 offset = ulist->start;
1317                 count = ulist->size;
1318
1319                 DEBUG(5,("release_posix_lock_posix_flavour: Real unlock: offset = %.0f, count = %.0f\n",
1320                         (double)offset, (double)count ));
1321
1322                 if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) {
1323                         ret = False;
1324                 }
1325         }
1326
1327         talloc_destroy(ul_ctx);
1328         return ret;
1329 }