Fix the mess with ldb includes.
[metze/samba/wip.git] / source3 / smbd / blocking.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Blocking Locking functions
4    Copyright (C) Jeremy Allison 1998-2003
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
20 #include "includes.h"
21 #include "smbd/globals.h"
22
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_LOCKING
25
26 /****************************************************************************
27  This is the structure to queue to implement blocking locks.
28  notify. It consists of the requesting SMB and the expiry time.
29 *****************************************************************************/
30
31 typedef struct blocking_lock_record {
32         struct blocking_lock_record *next;
33         struct blocking_lock_record *prev;
34         files_struct *fsp;
35         struct timeval expire_time;
36         int lock_num;
37         uint64_t offset;
38         uint64_t count;
39         uint32_t lock_pid;
40         uint32_t blocking_pid; /* PID that blocks us. */
41         enum brl_flavour lock_flav;
42         enum brl_type lock_type;
43         struct smb_request *req;
44 } blocking_lock_record;
45
46 /****************************************************************************
47  Determine if this is a secondary element of a chained SMB.
48   **************************************************************************/
49
50 static bool in_chained_smb(void)
51 {
52         return (chain_size != 0);
53 }
54
55 static void received_unlock_msg(struct messaging_context *msg,
56                                 void *private_data,
57                                 uint32_t msg_type,
58                                 struct server_id server_id,
59                                 DATA_BLOB *data);
60 static void process_blocking_lock_queue(void);
61
62 static void brl_timeout_fn(struct event_context *event_ctx,
63                            struct timed_event *te,
64                            struct timeval now,
65                            void *private_data)
66 {
67         SMB_ASSERT(brl_timeout == te);
68         TALLOC_FREE(brl_timeout);
69
70         change_to_root_user();  /* TODO: Possibly run all timed events as
71                                  * root */
72
73         process_blocking_lock_queue();
74 }
75
76 /****************************************************************************
77  After a change to blocking_lock_queue, recalculate the timed_event for the
78  next processing.
79 ****************************************************************************/
80
81 static bool recalc_brl_timeout(void)
82 {
83         blocking_lock_record *brl;
84         struct timeval next_timeout;
85
86         TALLOC_FREE(brl_timeout);
87
88         next_timeout = timeval_zero();  
89
90         for (brl = blocking_lock_queue; brl; brl = brl->next) {
91                 if (timeval_is_zero(&brl->expire_time)) {
92                         /*
93                          * If we're blocked on pid 0xFFFFFFFF this is
94                          * a POSIX lock, so calculate a timeout of
95                          * 10 seconds into the future.
96                          */
97                         if (brl->blocking_pid == 0xFFFFFFFF) {
98                                 struct timeval psx_to = timeval_current_ofs(10, 0);
99                                 next_timeout = timeval_min(&next_timeout, &psx_to);
100                         }
101
102                         continue;
103                 }
104
105                 if (timeval_is_zero(&next_timeout)) {
106                         next_timeout = brl->expire_time;
107                 }
108                 else {
109                         next_timeout = timeval_min(&next_timeout,
110                                                    &brl->expire_time);
111                 }
112         }
113
114         if (timeval_is_zero(&next_timeout)) {
115                 return True;
116         }
117
118         if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL,
119                                             next_timeout,
120                                             brl_timeout_fn, NULL))) {
121                 return False;
122         }
123
124         return True;
125 }
126
127
128 /****************************************************************************
129  Function to push a blocking lock request onto the lock queue.
130 ****************************************************************************/
131
132 bool push_blocking_lock_request( struct byte_range_lock *br_lck,
133                 struct smb_request *req,
134                 files_struct *fsp,
135                 int lock_timeout,
136                 int lock_num,
137                 uint32_t lock_pid,
138                 enum brl_type lock_type,
139                 enum brl_flavour lock_flav,
140                 uint64_t offset,
141                 uint64_t count,
142                 uint32_t blocking_pid)
143 {
144         blocking_lock_record *blr;
145         NTSTATUS status;
146
147         if(in_chained_smb() ) {
148                 DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
149                 return False;
150         }
151
152         /*
153          * Now queue an entry on the blocking lock queue. We setup
154          * the expiration time here.
155          */
156
157         blr = talloc(NULL, struct blocking_lock_record);
158         if (blr == NULL) {
159                 DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" ));
160                 return False;
161         }
162
163         blr->next = NULL;
164         blr->prev = NULL;
165
166         blr->fsp = fsp;
167         if (lock_timeout == -1) {
168                 blr->expire_time.tv_sec = 0;
169                 blr->expire_time.tv_usec = 0; /* Never expire. */
170         } else {
171                 blr->expire_time = timeval_current_ofs(lock_timeout/1000,
172                                         (lock_timeout % 1000) * 1000);
173         }
174         blr->lock_num = lock_num;
175         blr->lock_pid = lock_pid;
176         blr->blocking_pid = blocking_pid;
177         blr->lock_flav = lock_flav;
178         blr->lock_type = lock_type;
179         blr->offset = offset;
180         blr->count = count;
181
182         /* Add a pending lock record for this. */
183         status = brl_lock(smbd_messaging_context(), br_lck,
184                         lock_pid,
185                         procid_self(),
186                         offset,
187                         count,
188                         lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
189                         blr->lock_flav,
190                         lock_timeout ? True : False, /* blocking_lock. */
191                         NULL);
192
193         if (!NT_STATUS_IS_OK(status)) {
194                 DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
195                 DLIST_REMOVE(blocking_lock_queue, blr);
196                 TALLOC_FREE(blr);
197                 return False;
198         }
199
200         blr->req = talloc_move(blr, &req);
201
202         DLIST_ADD_END(blocking_lock_queue, blr, blocking_lock_record *);
203         recalc_brl_timeout();
204
205         /* Ensure we'll receive messages when this is unlocked. */
206         if (!blocking_lock_unlock_state) {
207                 messaging_register(smbd_messaging_context(), NULL,
208                                    MSG_SMB_UNLOCK, received_unlock_msg);
209                 blocking_lock_unlock_state = true;
210         }
211
212         DEBUG(3,("push_blocking_lock_request: lock request blocked with "
213                 "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n",
214                 (unsigned int)blr->expire_time.tv_sec,
215                 (unsigned int)blr->expire_time.tv_usec, lock_timeout,
216                 blr->fsp->fnum, blr->fsp->fsp_name ));
217
218         /* Push the MID of this packet on the signing queue. */
219         srv_defer_sign_response(blr->req->mid);
220
221         return True;
222 }
223
224 /****************************************************************************
225  Return a lockingX success SMB.
226 *****************************************************************************/
227
228 static void reply_lockingX_success(blocking_lock_record *blr)
229 {
230         reply_outbuf(blr->req, 2, 0);
231
232         /*
233          * As this message is a lockingX call we must handle
234          * any following chained message correctly.
235          * This is normally handled in construct_reply(),
236          * but as that calls switch_message, we can't use
237          * that here and must set up the chain info manually.
238          */
239
240         chain_reply(blr->req);
241         TALLOC_FREE(blr->req->outbuf);
242 }
243
244 /****************************************************************************
245  Return a generic lock fail error blocking call.
246 *****************************************************************************/
247
248 static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status)
249 {
250         /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
251            FILE_LOCK_CONFLICT! (tridge) */
252         if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
253                 status = NT_STATUS_FILE_LOCK_CONFLICT;
254         }
255
256         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
257                 /* Store the last lock error. */
258                 files_struct *fsp = blr->fsp;
259
260                 if (fsp) {
261                         fsp->last_lock_failure.context.smbpid = blr->lock_pid;
262                         fsp->last_lock_failure.context.tid = fsp->conn->cnum;
263                         fsp->last_lock_failure.context.pid = procid_self();
264                         fsp->last_lock_failure.start = blr->offset;
265                         fsp->last_lock_failure.size = blr->count;
266                         fsp->last_lock_failure.fnum = fsp->fnum;
267                         fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */
268                         fsp->last_lock_failure.lock_flav = blr->lock_flav;
269                 }
270         }
271
272         reply_nterror(blr->req, status);
273         if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
274                           blr->req->encrypted)) {
275                 exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
276         }
277         TALLOC_FREE(blr->req->outbuf);
278 }
279
280 /****************************************************************************
281  Return a lock fail error for a lockingX call. Undo all the locks we have 
282  obtained first.
283 *****************************************************************************/
284
285 static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
286 {
287         files_struct *fsp = blr->fsp;
288         uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
289         uint64_t count = (uint64_t)0, offset = (uint64_t) 0;
290         uint32 lock_pid;
291         unsigned char locktype = CVAL(blr->req->vwv+3, 0);
292         bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
293         uint8_t *data;
294         int i;
295
296         data = (uint8_t *)blr->req->buf
297                 + ((large_file_format ? 20 : 10)*num_ulocks);
298
299         /* 
300          * Data now points at the beginning of the list
301          * of smb_lkrng structs.
302          */
303
304         /*
305          * Ensure we don't do a remove on the lock that just failed,
306          * as under POSIX rules, if we have a lock already there, we
307          * will delete it (and we shouldn't) .....
308          */
309
310         for(i = blr->lock_num - 1; i >= 0; i--) {
311                 bool err;
312
313                 lock_pid = get_lock_pid( data, i, large_file_format);
314                 count = get_lock_count( data, i, large_file_format);
315                 offset = get_lock_offset( data, i, large_file_format, &err);
316
317                 /*
318                  * We know err cannot be set as if it was the lock
319                  * request would never have been queued. JRA.
320                  */
321
322                 do_unlock(smbd_messaging_context(),
323                         fsp,
324                         lock_pid,
325                         count,
326                         offset,
327                         WINDOWS_LOCK);
328         }
329
330         generic_blocking_lock_error(blr, status);
331 }
332
333 /****************************************************************************
334  Return a lock fail error.
335 *****************************************************************************/
336
337 static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
338 {
339         switch(blr->req->cmd) {
340         case SMBlockingX:
341                 reply_lockingX_error(blr, status);
342                 break;
343         case SMBtrans2:
344         case SMBtranss2:
345                 reply_nterror(blr->req, status);
346
347                 /*
348                  * construct_reply_common has done us the favor to pre-fill
349                  * the command field with SMBtranss2 which is wrong :-)
350                  */
351                 SCVAL(blr->req->outbuf,smb_com,SMBtrans2);
352
353                 if (!srv_send_smb(smbd_server_fd(),
354                                   (char *)blr->req->outbuf,
355                                   IS_CONN_ENCRYPTED(blr->fsp->conn))) {
356                         exit_server_cleanly("blocking_lock_reply_error: "
357                                             "srv_send_smb failed.");
358                 }
359                 TALLOC_FREE(blr->req->outbuf);
360                 break;
361         default:
362                 DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n"));
363                 exit_server("PANIC - unknown type on blocking lock queue");
364         }
365 }
366
367 /****************************************************************************
368  Attempt to finish off getting all pending blocking locks for a lockingX call.
369  Returns True if we want to be removed from the list.
370 *****************************************************************************/
371
372 static bool process_lockingX(blocking_lock_record *blr)
373 {
374         unsigned char locktype = CVAL(blr->req->vwv+3, 0);
375         files_struct *fsp = blr->fsp;
376         uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
377         uint16 num_locks = SVAL(blr->req->vwv+7, 0);
378         uint64_t count = (uint64_t)0, offset = (uint64_t)0;
379         uint32 lock_pid;
380         bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
381         uint8_t *data;
382         NTSTATUS status = NT_STATUS_OK;
383
384         data = (uint8_t *)blr->req->buf
385                 + ((large_file_format ? 20 : 10)*num_ulocks);
386
387         /* 
388          * Data now points at the beginning of the list
389          * of smb_lkrng structs.
390          */
391
392         for(; blr->lock_num < num_locks; blr->lock_num++) {
393                 struct byte_range_lock *br_lck = NULL;
394                 bool err;
395
396                 lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
397                 count = get_lock_count( data, blr->lock_num, large_file_format);
398                 offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
399
400                 /*
401                  * We know err cannot be set as if it was the lock
402                  * request would never have been queued. JRA.
403                  */
404                 errno = 0;
405                 br_lck = do_lock(smbd_messaging_context(),
406                                 fsp,
407                                 lock_pid,
408                                 count,
409                                 offset, 
410                                 ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
411                                         READ_LOCK : WRITE_LOCK),
412                                 WINDOWS_LOCK,
413                                 True,
414                                 &status,
415                                 &blr->blocking_pid);
416
417                 TALLOC_FREE(br_lck);
418
419                 if (NT_STATUS_IS_ERR(status)) {
420                         break;
421                 }
422         }
423
424         if(blr->lock_num == num_locks) {
425                 /*
426                  * Success - we got all the locks.
427                  */
428
429                 DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n",
430                          fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) );
431
432                 reply_lockingX_success(blr);
433                 return True;
434         }
435
436         if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
437             !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
438                 /*
439                  * We have other than a "can't get lock"
440                  * error. Free any locks we had and return an error.
441                  * Return True so we get dequeued.
442                  */
443                 blocking_lock_reply_error(blr, status);
444                 return True;
445         }
446
447         /*
448          * Still can't get all the locks - keep waiting.
449          */
450
451         DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
452 Waiting....\n", 
453                   blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum));
454
455         return False;
456 }
457
458 /****************************************************************************
459  Attempt to get the posix lock request from a SMBtrans2 call.
460  Returns True if we want to be removed from the list.
461 *****************************************************************************/
462
463 static bool process_trans2(blocking_lock_record *blr)
464 {
465         char params[2];
466         NTSTATUS status;
467         struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
468                                                 blr->fsp,
469                                                 blr->lock_pid,
470                                                 blr->count,
471                                                 blr->offset,
472                                                 blr->lock_type,
473                                                 blr->lock_flav,
474                                                 True,
475                                                 &status,
476                                                 &blr->blocking_pid);
477         TALLOC_FREE(br_lck);
478
479         if (!NT_STATUS_IS_OK(status)) {
480                 if (ERROR_WAS_LOCK_DENIED(status)) {
481                         /* Still can't get the lock, just keep waiting. */
482                         return False;
483                 }       
484                 /*
485                  * We have other than a "can't get lock"
486                  * error. Send an error and return True so we get dequeued.
487                  */
488                 blocking_lock_reply_error(blr, status);
489                 return True;
490         }
491
492         /* We finally got the lock, return success. */
493
494         SSVAL(params,0,0);
495         /* Fake up max_data_bytes here - we know it fits. */
496         send_trans2_replies(blr->fsp->conn, blr->req, params, 2, NULL, 0, 0xffff);
497         return True;
498 }
499
500
501 /****************************************************************************
502  Process a blocking lock SMB.
503  Returns True if we want to be removed from the list.
504 *****************************************************************************/
505
506 static bool blocking_lock_record_process(blocking_lock_record *blr)
507 {
508         switch(blr->req->cmd) {
509                 case SMBlockingX:
510                         return process_lockingX(blr);
511                 case SMBtrans2:
512                 case SMBtranss2:
513                         return process_trans2(blr);
514                 default:
515                         DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n"));
516                         exit_server("PANIC - unknown type on blocking lock queue");
517         }
518         return False; /* Keep compiler happy. */
519 }
520
521 /****************************************************************************
522  Cancel entries by fnum from the blocking lock pending queue.
523 *****************************************************************************/
524
525 void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
526 {
527         blocking_lock_record *blr, *next = NULL;
528
529         for(blr = blocking_lock_queue; blr; blr = next) {
530                 unsigned char locktype = 0;
531
532                 next = blr->next;
533                 if (blr->fsp->fnum != fsp->fnum) {
534                         continue;
535                 }
536
537                 if (blr->req->cmd == SMBlockingX) {
538                         locktype = CVAL(blr->req->vwv+3, 0);
539                 }
540
541                 DEBUG(10, ("remove_pending_lock_requests_by_fid - removing "
542                            "request type %d for file %s fnum = %d\n",
543                            blr->req->cmd, fsp->fsp_name, fsp->fnum));
544
545                 brl_lock_cancel(br_lck,
546                                 blr->lock_pid,
547                                 procid_self(),
548                                 blr->offset,
549                                 blr->count,
550                                 blr->lock_flav);
551
552                 blocking_lock_cancel(fsp,
553                                      blr->lock_pid,
554                                      blr->offset,
555                                      blr->count,
556                                      blr->lock_flav,
557                                      locktype,
558                                      NT_STATUS_RANGE_NOT_LOCKED);
559
560                 /* We're closing the file fsp here, so ensure
561                  * we don't have a dangling pointer. */
562                 blr->fsp = NULL;
563         }
564 }
565
566 /****************************************************************************
567  Delete entries by mid from the blocking lock pending queue. Always send reply.
568 *****************************************************************************/
569
570 void remove_pending_lock_requests_by_mid(int mid)
571 {
572         blocking_lock_record *blr, *next = NULL;
573
574         for(blr = blocking_lock_queue; blr; blr = next) {
575                 files_struct *fsp;
576                 struct byte_range_lock *br_lck;
577
578                 next = blr->next;
579
580                 if (blr->req->mid != mid) {
581                         continue;
582                 }
583
584                 fsp = blr->fsp;
585                 br_lck = brl_get_locks(talloc_tos(), fsp);
586
587                 if (br_lck) {
588                         DEBUG(10, ("remove_pending_lock_requests_by_mid - "
589                                    "removing request type %d for file %s fnum "
590                                    "= %d\n", blr->req->cmd, fsp->fsp_name,
591                                    fsp->fnum ));
592
593                         brl_lock_cancel(br_lck,
594                                         blr->lock_pid,
595                                         procid_self(),
596                                         blr->offset,
597                                         blr->count,
598                                         blr->lock_flav);
599                         TALLOC_FREE(br_lck);
600                 }
601
602                 blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
603                 DLIST_REMOVE(blocking_lock_queue, blr);
604                 TALLOC_FREE(blr);
605         }
606 }
607
608 /****************************************************************************
609  Is this mid a blocking lock request on the queue ?
610 *****************************************************************************/
611
612 bool blocking_lock_was_deferred(int mid)
613 {
614         blocking_lock_record *blr, *next = NULL;
615
616         for(blr = blocking_lock_queue; blr; blr = next) {
617                 next = blr->next;
618                 if(blr->req->mid == mid) {
619                         return True;
620                 }
621         }
622         return False;
623 }
624
625 /****************************************************************************
626   Set a flag as an unlock request affects one of our pending locks.
627 *****************************************************************************/
628
629 static void received_unlock_msg(struct messaging_context *msg,
630                                 void *private_data,
631                                 uint32_t msg_type,
632                                 struct server_id server_id,
633                                 DATA_BLOB *data)
634 {
635         DEBUG(10,("received_unlock_msg\n"));
636         process_blocking_lock_queue();
637 }
638
639 /****************************************************************************
640  Process the blocking lock queue. Note that this is only called as root.
641 *****************************************************************************/
642
643 static void process_blocking_lock_queue(void)
644 {
645         struct timeval tv_curr = timeval_current();
646         blocking_lock_record *blr, *next = NULL;
647         bool recalc_timeout = False;
648
649         /*
650          * Go through the queue and see if we can get any of the locks.
651          */
652
653         for (blr = blocking_lock_queue; blr; blr = next) {
654
655                 next = blr->next;
656
657                 /*
658                  * Go through the remaining locks and try and obtain them.
659                  * The call returns True if all locks were obtained successfully
660                  * and False if we still need to wait.
661                  */
662
663                 if(blocking_lock_record_process(blr)) {
664                         struct byte_range_lock *br_lck = brl_get_locks(
665                                 talloc_tos(), blr->fsp);
666
667                         if (br_lck) {
668                                 brl_lock_cancel(br_lck,
669                                         blr->lock_pid,
670                                         procid_self(),
671                                         blr->offset,
672                                         blr->count,
673                                         blr->lock_flav);
674                                 TALLOC_FREE(br_lck);
675                         }
676
677                         DLIST_REMOVE(blocking_lock_queue, blr);
678                         TALLOC_FREE(blr);
679                         recalc_timeout = True;
680                         continue;
681                 }
682
683                 /*
684                  * We couldn't get the locks for this record on the list.
685                  * If the time has expired, return a lock error.
686                  */
687
688                 if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
689                         struct byte_range_lock *br_lck = brl_get_locks(
690                                 talloc_tos(), blr->fsp);
691
692                         /*
693                          * Lock expired - throw away all previously
694                          * obtained locks and return lock error.
695                          */
696
697                         if (br_lck) {
698                                 DEBUG(5,("process_blocking_lock_queue: "
699                                          "pending lock fnum = %d for file %s "
700                                          "timed out.\n", blr->fsp->fnum,
701                                          blr->fsp->fsp_name ));
702
703                                 brl_lock_cancel(br_lck,
704                                         blr->lock_pid,
705                                         procid_self(),
706                                         blr->offset,
707                                         blr->count,
708                                         blr->lock_flav);
709                                 TALLOC_FREE(br_lck);
710                         }
711
712                         blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
713                         DLIST_REMOVE(blocking_lock_queue, blr);
714                         TALLOC_FREE(blr);
715                         recalc_timeout = True;
716                 }
717         }
718
719         if (recalc_timeout) {
720                 recalc_brl_timeout();
721         }
722 }
723
724 /****************************************************************************
725  Handle a cancel message. Lock already moved onto the cancel queue.
726 *****************************************************************************/
727
728 #define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
729
730 static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
731                                                  void *private_data,
732                                                  uint32_t msg_type,
733                                                  struct server_id server_id,
734                                                  DATA_BLOB *data)
735 {
736         NTSTATUS err;
737         const char *msg = (const char *)data->data;
738         blocking_lock_record *blr;
739
740         if (data->data == NULL) {
741                 smb_panic("process_blocking_lock_cancel_message: null msg");
742         }
743
744         if (data->length != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
745                 DEBUG(0, ("process_blocking_lock_cancel_message: "
746                           "Got invalid msg len %d\n", (int)data->length));
747                 smb_panic("process_blocking_lock_cancel_message: bad msg");
748         }
749
750         memcpy(&blr, msg, sizeof(blr));
751         memcpy(&err, &msg[sizeof(blr)], sizeof(NTSTATUS));
752
753         DEBUG(10,("process_blocking_lock_cancel_message: returning error %s\n",
754                 nt_errstr(err) ));
755
756         blocking_lock_reply_error(blr, err);
757         DLIST_REMOVE(blocking_lock_cancelled_queue, blr);
758         TALLOC_FREE(blr);
759 }
760
761 /****************************************************************************
762  Send ourselves a blocking lock cancelled message. Handled asynchronously above.
763 *****************************************************************************/
764
765 bool blocking_lock_cancel(files_struct *fsp,
766                         uint32 lock_pid,
767                         uint64_t offset,
768                         uint64_t count,
769                         enum brl_flavour lock_flav,
770                         unsigned char locktype,
771                         NTSTATUS err)
772 {
773         char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
774         blocking_lock_record *blr;
775
776         if (!blocking_lock_cancel_state) {
777                 /* Register our message. */
778                 messaging_register(smbd_messaging_context(), NULL,
779                                    MSG_SMB_BLOCKING_LOCK_CANCEL,
780                                    process_blocking_lock_cancel_message);
781
782                 blocking_lock_cancel_state = True;
783         }
784
785         for (blr = blocking_lock_queue; blr; blr = blr->next) {
786                 if (fsp == blr->fsp &&
787                                 lock_pid == blr->lock_pid &&
788                                 offset == blr->offset &&
789                                 count == blr->count &&
790                                 lock_flav == blr->lock_flav) {
791                         break;
792                 }
793         }
794
795         if (!blr) {
796                 return False;
797         }
798
799         /* Check the flags are right. */
800         if (blr->req->cmd == SMBlockingX &&
801                 (locktype & LOCKING_ANDX_LARGE_FILES) !=
802                         (CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) {
803                 return False;
804         }
805
806         /* Move to cancelled queue. */
807         DLIST_REMOVE(blocking_lock_queue, blr);
808         DLIST_ADD(blocking_lock_cancelled_queue, blr);
809
810         /* Create the message. */
811         memcpy(msg, &blr, sizeof(blr));
812         memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS));
813
814         messaging_send_buf(smbd_messaging_context(), procid_self(),
815                            MSG_SMB_BLOCKING_LOCK_CANCEL,
816                            (uint8 *)&msg, sizeof(msg));
817
818         return True;
819 }