~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/smbd/blocking.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 2 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, write to the Free Software
18
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
*/
20
 
 
21
 
#include "includes.h"
22
 
 
23
 
/****************************************************************************
24
 
 This is the structure to queue to implement blocking locks.
25
 
 notify. It consists of the requesting SMB and the expiry time.
26
 
*****************************************************************************/
27
 
 
28
 
typedef struct _blocking_lock_record {
29
 
        struct _blocking_lock_record *next;
30
 
        struct _blocking_lock_record *prev;
31
 
        int com_type;
32
 
        files_struct *fsp;
33
 
        time_t expire_time;
34
 
        int lock_num;
35
 
        SMB_BIG_UINT offset;
36
 
        SMB_BIG_UINT count;
37
 
        uint32 lock_pid;
38
 
        enum brl_flavour lock_flav;
39
 
        enum brl_type lock_type;
40
 
        char *inbuf;
41
 
        int length;
42
 
} blocking_lock_record;
43
 
 
44
 
static blocking_lock_record *blocking_lock_queue;
45
 
 
46
 
/****************************************************************************
47
 
 Destructor for the above structure.
48
 
****************************************************************************/
49
 
 
50
 
static void free_blocking_lock_record(blocking_lock_record *blr)
51
 
{
52
 
        DLIST_REMOVE(blocking_lock_queue, blr);
53
 
        SAFE_FREE(blr->inbuf);
54
 
        SAFE_FREE(blr);
55
 
}
56
 
 
57
 
/****************************************************************************
58
 
 Determine if this is a secondary element of a chained SMB.
59
 
  **************************************************************************/
60
 
 
61
 
static BOOL in_chained_smb(void)
62
 
{
63
 
        return (chain_size != 0);
64
 
}
65
 
 
66
 
static void received_unlock_msg(int msg_type, struct process_id src,
67
 
                                void *buf, size_t len);
68
 
 
69
 
/****************************************************************************
70
 
 Function to push a blocking lock request onto the lock queue.
71
 
****************************************************************************/
72
 
 
73
 
BOOL push_blocking_lock_request( char *inbuf, int length,
74
 
                files_struct *fsp,
75
 
                int lock_timeout,
76
 
                int lock_num,
77
 
                uint32 lock_pid,
78
 
                enum brl_type lock_type,
79
 
                enum brl_flavour lock_flav,
80
 
                SMB_BIG_UINT offset, SMB_BIG_UINT count)
81
 
{
82
 
        static BOOL set_lock_msg;
83
 
        blocking_lock_record *blr, *tmp;
84
 
        BOOL my_lock_ctx = False;
85
 
        struct byte_range_lock *br_lck = NULL;
86
 
        NTSTATUS status;
87
 
 
88
 
        if(in_chained_smb() ) {
89
 
                DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
90
 
                return False;
91
 
        }
92
 
 
93
 
        /*
94
 
         * Now queue an entry on the blocking lock queue. We setup
95
 
         * the expiration time here.
96
 
         */
97
 
 
98
 
        if((blr = SMB_MALLOC_P(blocking_lock_record)) == NULL) {
99
 
                DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" ));
100
 
                return False;
101
 
        }
102
 
 
103
 
        blr->next = NULL;
104
 
        blr->prev = NULL;
105
 
 
106
 
        if((blr->inbuf = (char *)SMB_MALLOC(length)) == NULL) {
107
 
                DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" ));
108
 
                SAFE_FREE(blr);
109
 
                return False;
110
 
        }
111
 
 
112
 
        blr->com_type = CVAL(inbuf,smb_com);
113
 
        blr->fsp = fsp;
114
 
        blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout;
115
 
        blr->lock_num = lock_num;
116
 
        blr->lock_pid = lock_pid;
117
 
        blr->lock_flav = lock_flav;
118
 
        blr->lock_type = lock_type;
119
 
        blr->offset = offset;
120
 
        blr->count = count;
121
 
        memcpy(blr->inbuf, inbuf, length);
122
 
        blr->length = length;
123
 
 
124
 
        br_lck = brl_get_locks(NULL, blr->fsp);
125
 
        if (!br_lck) {
126
 
                free_blocking_lock_record(blr);
127
 
                return False;
128
 
        }
129
 
 
130
 
        /* Add a pending lock record for this. */
131
 
        status = brl_lock(br_lck,
132
 
                        lock_pid,
133
 
                        procid_self(),
134
 
                        offset,
135
 
                        count,
136
 
                        PENDING_LOCK,
137
 
                        blr->lock_flav,
138
 
                        &my_lock_ctx);
139
 
        TALLOC_FREE(br_lck);
140
 
 
141
 
        if (!NT_STATUS_IS_OK(status)) {
142
 
                DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
143
 
                free_blocking_lock_record(blr);
144
 
                return False;
145
 
        }
146
 
 
147
 
        DLIST_ADD_END(blocking_lock_queue, blr, tmp);
148
 
 
149
 
        /* Ensure we'll receive messages when this is unlocked. */
150
 
        if (!set_lock_msg) {
151
 
                message_register(MSG_SMB_UNLOCK, received_unlock_msg);
152
 
                set_lock_msg = True;
153
 
        }
154
 
 
155
 
        DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with expiry time %d (+%d) \
156
 
for fnum = %d, name = %s\n", length, (int)blr->expire_time, lock_timeout,
157
 
                blr->fsp->fnum, blr->fsp->fsp_name ));
158
 
 
159
 
        /* Push the MID of this packet on the signing queue. */
160
 
        srv_defer_sign_response(SVAL(inbuf,smb_mid));
161
 
 
162
 
        return True;
163
 
}
164
 
 
165
 
/****************************************************************************
166
 
 Return a smd with a given size.
167
 
*****************************************************************************/
168
 
 
169
 
static void send_blocking_reply(char *outbuf, int outsize)
170
 
{
171
 
        if(outsize > 4)
172
 
                smb_setlen(outbuf,outsize - 4);
173
 
 
174
 
        if (!send_smb(smbd_server_fd(),outbuf))
175
 
                exit_server("send_blocking_reply: send_smb failed.");
176
 
}
177
 
 
178
 
/****************************************************************************
179
 
 Return a lockingX success SMB.
180
 
*****************************************************************************/
181
 
 
182
 
static void reply_lockingX_success(blocking_lock_record *blr)
183
 
{
184
 
        char *outbuf = get_OutBuffer();
185
 
        int bufsize = BUFFER_SIZE;
186
 
        char *inbuf = blr->inbuf;
187
 
        int outsize = 0;
188
 
 
189
 
        construct_reply_common(inbuf, outbuf);
190
 
        set_message(outbuf,2,0,True);
191
 
 
192
 
        /*
193
 
         * As this message is a lockingX call we must handle
194
 
         * any following chained message correctly.
195
 
         * This is normally handled in construct_reply(),
196
 
         * but as that calls switch_message, we can't use
197
 
         * that here and must set up the chain info manually.
198
 
         */
199
 
 
200
 
        outsize = chain_reply(inbuf,outbuf,blr->length,bufsize);
201
 
 
202
 
        outsize += chain_size;
203
 
 
204
 
        send_blocking_reply(outbuf,outsize);
205
 
}
206
 
 
207
 
/****************************************************************************
208
 
 Return a generic lock fail error blocking call.
209
 
*****************************************************************************/
210
 
 
211
 
static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status)
212
 
{
213
 
        char *outbuf = get_OutBuffer();
214
 
        char *inbuf = blr->inbuf;
215
 
        construct_reply_common(inbuf, outbuf);
216
 
 
217
 
        /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
218
 
           FILE_LOCK_CONFLICT! (tridge) */
219
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
220
 
                status = NT_STATUS_FILE_LOCK_CONFLICT;
221
 
        }
222
 
 
223
 
        ERROR_NT(status);
224
 
        if (!send_smb(smbd_server_fd(),outbuf))
225
 
                exit_server("generic_blocking_lock_error: send_smb failed.");
226
 
}
227
 
 
228
 
/****************************************************************************
229
 
 Return a lock fail error for a lockingX call. Undo all the locks we have 
230
 
 obtained first.
231
 
*****************************************************************************/
232
 
 
233
 
static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
234
 
{
235
 
        char *inbuf = blr->inbuf;
236
 
        files_struct *fsp = blr->fsp;
237
 
        uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
238
 
        SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0;
239
 
        uint32 lock_pid;
240
 
        unsigned char locktype = CVAL(inbuf,smb_vwv3);
241
 
        BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
242
 
        char *data;
243
 
        int i;
244
 
 
245
 
        data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
246
 
        
247
 
        /* 
248
 
         * Data now points at the beginning of the list
249
 
         * of smb_lkrng structs.
250
 
         */
251
 
 
252
 
        /*
253
 
         * Ensure we don't do a remove on the lock that just failed,
254
 
         * as under POSIX rules, if we have a lock already there, we
255
 
         * will delete it (and we shouldn't) .....
256
 
         */
257
 
        
258
 
        for(i = blr->lock_num - 1; i >= 0; i--) {
259
 
                BOOL err;
260
 
                
261
 
                lock_pid = get_lock_pid( data, i, large_file_format);
262
 
                count = get_lock_count( data, i, large_file_format);
263
 
                offset = get_lock_offset( data, i, large_file_format, &err);
264
 
                
265
 
                /*
266
 
                 * We know err cannot be set as if it was the lock
267
 
                 * request would never have been queued. JRA.
268
 
                 */
269
 
                
270
 
                do_unlock(fsp,
271
 
                        lock_pid,
272
 
                        count,
273
 
                        offset,
274
 
                        WINDOWS_LOCK);
275
 
        }
276
 
        
277
 
        generic_blocking_lock_error(blr, status);
278
 
}
279
 
 
280
 
/****************************************************************************
281
 
 Return a lock fail error.
282
 
*****************************************************************************/
283
 
 
284
 
static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
285
 
{
286
 
        switch(blr->com_type) {
287
 
#if 0
288
 
        /* We no longer push blocking lock requests for anything but lockingX and trans2. */
289
 
        case SMBlock:
290
 
        case SMBlockread:
291
 
                generic_blocking_lock_error(blr, status);
292
 
                break;
293
 
#endif
294
 
        case SMBlockingX:
295
 
                reply_lockingX_error(blr, status);
296
 
                break;
297
 
        case SMBtrans2:
298
 
        case SMBtranss2:
299
 
                {
300
 
                        char *outbuf = get_OutBuffer();
301
 
                        char *inbuf = blr->inbuf;
302
 
                        construct_reply_common(inbuf, outbuf);
303
 
                        /* construct_reply_common has done us the favor to pre-fill the
304
 
                         * command field with SMBtranss2 which is wrong :-)
305
 
                         */
306
 
                        SCVAL(outbuf,smb_com,SMBtrans2);
307
 
                        ERROR_NT(status);
308
 
                        if (!send_smb(smbd_server_fd(),outbuf)) {
309
 
                                exit_server("blocking_lock_reply_error: send_smb failed.");
310
 
                        }
311
 
                        break;
312
 
                }
313
 
        default:
314
 
                DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n"));
315
 
                exit_server("PANIC - unknown type on blocking lock queue");
316
 
        }
317
 
}
318
 
 
319
 
#if 0
320
 
/* We no longer push blocking lock requests for anything but lockingX and trans2. */
321
 
 
322
 
/****************************************************************************
323
 
 Attempt to finish off getting all pending blocking locks for a lockread call.
324
 
 Returns True if we want to be removed from the list.
325
 
*****************************************************************************/
326
 
 
327
 
static BOOL process_lockread(blocking_lock_record *blr)
328
 
{
329
 
        char *outbuf = get_OutBuffer();
330
 
        char *inbuf = blr->inbuf;
331
 
        ssize_t nread = -1;
332
 
        char *data, *p;
333
 
        int outsize = 0;
334
 
        SMB_BIG_UINT startpos;
335
 
        size_t numtoread;
336
 
        NTSTATUS status;
337
 
        files_struct *fsp = blr->fsp;
338
 
        BOOL my_lock_ctx = False;
339
 
 
340
 
        numtoread = SVAL(inbuf,smb_vwv1);
341
 
        startpos = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv2);
342
 
        
343
 
        numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
344
 
        data = smb_buf(outbuf) + 3;
345
 
 
346
 
        status = do_lock_spin(fsp,
347
 
                                (uint32)SVAL(inbuf,smb_pid),
348
 
                                (SMB_BIG_UINT)numtoread,
349
 
                                startpos,
350
 
                                READ_LOCK,
351
 
                                WINDOWS_LOCK,
352
 
                                &my_lock_ctx);
353
 
 
354
 
        if (NT_STATUS_V(status)) {
355
 
                if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
356
 
                        !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
357
 
                        /*
358
 
                         * We have other than a "can't get lock"
359
 
                         * error. Send an error.
360
 
                         * Return True so we get dequeued.
361
 
                         */
362
 
                        generic_blocking_lock_error(blr, status);
363
 
                        return True;
364
 
                }
365
 
 
366
 
                /*
367
 
                 * Still waiting for lock....
368
 
                 */
369
 
                
370
 
                DEBUG(10,("process_lockread: failed to get lock for file = %s. Still waiting....\n",
371
 
                          fsp->fsp_name));
372
 
                return False;
373
 
        }
374
 
 
375
 
        nread = read_file(fsp,data,startpos,numtoread);
376
 
 
377
 
        if (nread < 0) {
378
 
                generic_blocking_lock_error(blr,NT_STATUS_ACCESS_DENIED);
379
 
                return True;
380
 
        }
381
 
        
382
 
        construct_reply_common(inbuf, outbuf);
383
 
        outsize = set_message(outbuf,5,0,True);
384
 
        
385
 
        outsize += nread;
386
 
        SSVAL(outbuf,smb_vwv0,nread);
387
 
        SSVAL(outbuf,smb_vwv5,nread+3);
388
 
        p = smb_buf(outbuf);
389
 
        *p++ = 1;
390
 
        SSVAL(p,0,nread); p += 2;
391
 
        set_message_end(outbuf, p+nread);
392
 
        
393
 
        DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%lu nread=%ld\n",
394
 
                   fsp->fsp_name, fsp->fnum, (unsigned long)numtoread, (long)nread ) );
395
 
        
396
 
        send_blocking_reply(outbuf,outsize);
397
 
        return True;
398
 
}
399
 
 
400
 
/****************************************************************************
401
 
 Attempt to finish off getting all pending blocking locks for a lock call.
402
 
 Returns True if we want to be removed from the list.
403
 
*****************************************************************************/
404
 
 
405
 
static BOOL process_lock(blocking_lock_record *blr)
406
 
{
407
 
        char *outbuf = get_OutBuffer();
408
 
        char *inbuf = blr->inbuf;
409
 
        int outsize;
410
 
        SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
411
 
        NTSTATUS status;
412
 
        files_struct *fsp = blr->fsp;
413
 
        BOOL my_lock_ctx = False;
414
 
 
415
 
        count = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
416
 
        offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
417
 
 
418
 
        errno = 0;
419
 
        status = do_lock_spin(fsp,
420
 
                                (uint32)SVAL(inbuf,smb_pid),
421
 
                                count,
422
 
                                offset,
423
 
                                WRITE_LOCK,
424
 
                                WINDOWS_LOCK,
425
 
                                &my_lock_ctx);
426
 
 
427
 
        if (NT_STATUS_IS_ERR(status)) {
428
 
                if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
429
 
                        !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
430
 
                        /*
431
 
                         * We have other than a "can't get lock"
432
 
                         * error. Send an error.
433
 
                         * Return True so we get dequeued.
434
 
                         */
435
 
                        
436
 
                        blocking_lock_reply_error(blr, status);
437
 
                        return True;
438
 
                }
439
 
                /*
440
 
                 * Still can't get the lock - keep waiting.
441
 
                 */
442
 
                DEBUG(10,("process_lock: failed to get lock for file = %s. Still waiting....\n",
443
 
                          fsp->fsp_name));
444
 
                return False;
445
 
        }
446
 
 
447
 
        /*
448
 
         * Success - we got the lock.
449
 
         */
450
 
        
451
 
        DEBUG(3,("process_lock : file=%s fnum=%d offset=%.0f count=%.0f\n",
452
 
                 fsp->fsp_name, fsp->fnum, (double)offset, (double)count));
453
 
        
454
 
        construct_reply_common(inbuf, outbuf);
455
 
        outsize = set_message(outbuf,0,0,True);
456
 
        send_blocking_reply(outbuf,outsize);
457
 
        return True;
458
 
}
459
 
#endif
460
 
 
461
 
/****************************************************************************
462
 
 Attempt to finish off getting all pending blocking locks for a lockingX call.
463
 
 Returns True if we want to be removed from the list.
464
 
*****************************************************************************/
465
 
 
466
 
static BOOL process_lockingX(blocking_lock_record *blr)
467
 
{
468
 
        char *inbuf = blr->inbuf;
469
 
        unsigned char locktype = CVAL(inbuf,smb_vwv3);
470
 
        files_struct *fsp = blr->fsp;
471
 
        uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
472
 
        uint16 num_locks = SVAL(inbuf,smb_vwv7);
473
 
        SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
474
 
        uint32 lock_pid;
475
 
        BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
476
 
        char *data;
477
 
        BOOL my_lock_ctx = False;
478
 
        NTSTATUS status = NT_STATUS_OK;
479
 
 
480
 
        data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
481
 
 
482
 
        /* 
483
 
         * Data now points at the beginning of the list
484
 
         * of smb_lkrng structs.
485
 
         */
486
 
        
487
 
        for(; blr->lock_num < num_locks; blr->lock_num++) {
488
 
                BOOL err;
489
 
 
490
 
                lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
491
 
                count = get_lock_count( data, blr->lock_num, large_file_format);
492
 
                offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
493
 
                
494
 
                /*
495
 
                 * We know err cannot be set as if it was the lock
496
 
                 * request would never have been queued. JRA.
497
 
                 */
498
 
                errno = 0;
499
 
                status = do_lock_spin(fsp,
500
 
                                lock_pid,
501
 
                                count,
502
 
                                offset, 
503
 
                                ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
504
 
                                WINDOWS_LOCK,
505
 
                                &my_lock_ctx);
506
 
 
507
 
                if (NT_STATUS_IS_ERR(status)) {
508
 
                        break;
509
 
                }
510
 
        }
511
 
 
512
 
        if(blr->lock_num == num_locks) {
513
 
                /*
514
 
                 * Success - we got all the locks.
515
 
                 */
516
 
                
517
 
                DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n",
518
 
                         fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) );
519
 
 
520
 
                reply_lockingX_success(blr);
521
 
                return True;
522
 
        } else if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
523
 
                        !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
524
 
                        /*
525
 
                         * We have other than a "can't get lock"
526
 
                         * error. Free any locks we had and return an error.
527
 
                         * Return True so we get dequeued.
528
 
                         */
529
 
                
530
 
                blocking_lock_reply_error(blr, status);
531
 
                return True;
532
 
        }
533
 
 
534
 
        /*
535
 
         * Still can't get all the locks - keep waiting.
536
 
         */
537
 
        
538
 
        DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
539
 
Waiting....\n", 
540
 
                  blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum));
541
 
        
542
 
        return False;
543
 
}
544
 
 
545
 
/****************************************************************************
546
 
 Attempt to get the posix lock request from a SMBtrans2 call.
547
 
 Returns True if we want to be removed from the list.
548
 
*****************************************************************************/
549
 
 
550
 
static BOOL process_trans2(blocking_lock_record *blr)
551
 
{
552
 
        extern int max_send;
553
 
        char *inbuf = blr->inbuf;
554
 
        char *outbuf;
555
 
        BOOL my_lock_ctx = False;
556
 
        char params[2];
557
 
        NTSTATUS status;
558
 
 
559
 
        status = do_lock(blr->fsp,
560
 
                        blr->lock_pid,
561
 
                        blr->count,
562
 
                        blr->offset,
563
 
                        blr->lock_type,
564
 
                        blr->lock_flav,
565
 
                        &my_lock_ctx);
566
 
 
567
 
        if (!NT_STATUS_IS_OK(status)) {
568
 
                if (ERROR_WAS_LOCK_DENIED(status)) {
569
 
                        /* Still can't get the lock, just keep waiting. */
570
 
                        return False;
571
 
                }       
572
 
                /*
573
 
                 * We have other than a "can't get lock"
574
 
                 * error. Send an error and return True so we get dequeued.
575
 
                 */
576
 
                blocking_lock_reply_error(blr, status);
577
 
                return True;
578
 
        }
579
 
 
580
 
        /* We finally got the lock, return success. */
581
 
        outbuf = get_OutBuffer();
582
 
        construct_reply_common(inbuf, outbuf);
583
 
        SCVAL(outbuf,smb_com,SMBtrans2);
584
 
        SSVAL(params,0,0);
585
 
        send_trans2_replies(outbuf, max_send, params, 2, NULL, 0);
586
 
        return True;
587
 
}
588
 
 
589
 
 
590
 
/****************************************************************************
591
 
 Process a blocking lock SMB.
592
 
 Returns True if we want to be removed from the list.
593
 
*****************************************************************************/
594
 
 
595
 
static BOOL blocking_lock_record_process(blocking_lock_record *blr)
596
 
{
597
 
        switch(blr->com_type) {
598
 
#if 0
599
 
                /* We no longer push blocking lock requests for anything but lockingX and trans2. */
600
 
                case SMBlock:
601
 
                        return process_lock(blr);
602
 
                case SMBlockread:
603
 
                        return process_lockread(blr);
604
 
#endif
605
 
                case SMBlockingX:
606
 
                        return process_lockingX(blr);
607
 
                case SMBtrans2:
608
 
                case SMBtranss2:
609
 
                        return process_trans2(blr);
610
 
                default:
611
 
                        DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n"));
612
 
                        exit_server("PANIC - unknown type on blocking lock queue");
613
 
        }
614
 
        return False; /* Keep compiler happy. */
615
 
}
616
 
 
617
 
/****************************************************************************
618
 
 Delete entries by fnum from the blocking lock pending queue.
619
 
*****************************************************************************/
620
 
 
621
 
void remove_pending_lock_requests_by_fid(files_struct *fsp)
622
 
{
623
 
        blocking_lock_record *blr, *next = NULL;
624
 
 
625
 
        for(blr = blocking_lock_queue; blr; blr = next) {
626
 
                next = blr->next;
627
 
                if(blr->fsp->fnum == fsp->fnum) {
628
 
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
629
 
 
630
 
                        if (br_lck) {
631
 
                                DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
632
 
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
633
 
 
634
 
                                brl_remove_pending_lock(br_lck,
635
 
                                        blr->lock_pid,
636
 
                                        procid_self(),
637
 
                                        blr->offset,
638
 
                                        blr->count,
639
 
                                        blr->lock_flav);
640
 
                                TALLOC_FREE(br_lck);
641
 
 
642
 
                        }
643
 
 
644
 
                        free_blocking_lock_record(blr);
645
 
                }
646
 
        }
647
 
}
648
 
 
649
 
/****************************************************************************
650
 
 Delete entries by mid from the blocking lock pending queue. Always send reply.
651
 
*****************************************************************************/
652
 
 
653
 
void remove_pending_lock_requests_by_mid(int mid)
654
 
{
655
 
        blocking_lock_record *blr, *next = NULL;
656
 
 
657
 
        for(blr = blocking_lock_queue; blr; blr = next) {
658
 
                next = blr->next;
659
 
                if(SVAL(blr->inbuf,smb_mid) == mid) {
660
 
                        files_struct *fsp = blr->fsp;
661
 
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
662
 
 
663
 
                        if (br_lck) {
664
 
                                DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
665
 
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
666
 
 
667
 
                                brl_remove_pending_lock(br_lck,
668
 
                                        blr->lock_pid,
669
 
                                        procid_self(),
670
 
                                        blr->offset,
671
 
                                        blr->count,
672
 
                                        blr->lock_flav);
673
 
                                TALLOC_FREE(br_lck);
674
 
                        }
675
 
 
676
 
                        blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
677
 
                        free_blocking_lock_record(blr);
678
 
                }
679
 
        }
680
 
}
681
 
 
682
 
/****************************************************************************
683
 
  Set a flag as an unlock request affects one of our pending locks.
684
 
*****************************************************************************/
685
 
 
686
 
static void received_unlock_msg(int msg_type, struct process_id src,
687
 
                                void *buf, size_t len)
688
 
{
689
 
        DEBUG(10,("received_unlock_msg\n"));
690
 
        process_blocking_lock_queue(time(NULL));
691
 
}
692
 
 
693
 
/****************************************************************************
694
 
 Return the number of seconds to the next blocking locks timeout, or default_timeout
695
 
*****************************************************************************/
696
 
 
697
 
unsigned blocking_locks_timeout(unsigned default_timeout)
698
 
{
699
 
        unsigned timeout = default_timeout;
700
 
        time_t t;
701
 
        blocking_lock_record *blr = blocking_lock_queue;
702
 
 
703
 
        /* note that we avoid the time() syscall if there are no blocking locks */
704
 
        if (!blr)
705
 
                return timeout;
706
 
 
707
 
        t = time(NULL);
708
 
 
709
 
        for (; blr; blr = blr->next) {
710
 
                if ((blr->expire_time != (time_t)-1) &&
711
 
                                        (timeout > (blr->expire_time - t))) {
712
 
                        timeout = blr->expire_time - t;
713
 
                }
714
 
        }
715
 
 
716
 
        if (timeout < 1)
717
 
                timeout = 1;
718
 
 
719
 
        return timeout;
720
 
}
721
 
 
722
 
/****************************************************************************
723
 
 Process the blocking lock queue. Note that this is only called as root.
724
 
*****************************************************************************/
725
 
 
726
 
void process_blocking_lock_queue(time_t t)
727
 
{
728
 
        blocking_lock_record *blr, *next = NULL;
729
 
 
730
 
        /*
731
 
         * Go through the queue and see if we can get any of the locks.
732
 
         */
733
 
 
734
 
        for (blr = blocking_lock_queue; blr; blr = next) {
735
 
                connection_struct *conn = NULL;
736
 
                uint16 vuid;
737
 
                files_struct *fsp = NULL;
738
 
 
739
 
                next = blr->next;
740
 
 
741
 
                /*
742
 
                 * Ensure we don't have any old chain_fsp values
743
 
                 * sitting around....
744
 
                 */
745
 
                chain_size = 0;
746
 
                file_chain_reset();
747
 
                fsp = blr->fsp;
748
 
 
749
 
                conn = conn_find(SVAL(blr->inbuf,smb_tid));
750
 
                vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
751
 
                                SVAL(blr->inbuf,smb_uid);
752
 
 
753
 
                DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n",
754
 
                        fsp->fnum, fsp->fsp_name ));
755
 
 
756
 
                if((blr->expire_time != -1) && (blr->expire_time <= t)) {
757
 
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
758
 
 
759
 
                        /*
760
 
                         * Lock expired - throw away all previously
761
 
                         * obtained locks and return lock error.
762
 
                         */
763
 
 
764
 
                        if (br_lck) {
765
 
                                DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
766
 
                                        fsp->fnum, fsp->fsp_name ));
767
 
 
768
 
                                brl_remove_pending_lock(br_lck,
769
 
                                        blr->lock_pid,
770
 
                                        procid_self(),
771
 
                                        blr->offset,
772
 
                                        blr->count,
773
 
                                        blr->lock_flav);
774
 
                                TALLOC_FREE(br_lck);
775
 
                        }
776
 
 
777
 
                        blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
778
 
                        free_blocking_lock_record(blr);
779
 
                        continue;
780
 
                }
781
 
 
782
 
                if(!change_to_user(conn,vuid)) {
783
 
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
784
 
 
785
 
                        /*
786
 
                         * Remove the entry and return an error to the client.
787
 
                         */
788
 
 
789
 
                        if (br_lck) {
790
 
                                brl_remove_pending_lock(br_lck,
791
 
                                        blr->lock_pid,
792
 
                                        procid_self(),
793
 
                                        blr->offset,
794
 
                                        blr->count,
795
 
                                        blr->lock_flav);
796
 
                                TALLOC_FREE(br_lck);
797
 
                        }
798
 
 
799
 
                        DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
800
 
                                vuid ));
801
 
                        blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
802
 
                        free_blocking_lock_record(blr);
803
 
                        continue;
804
 
                }
805
 
 
806
 
                if(!set_current_service(conn,SVAL(blr->inbuf,smb_flg),True)) {
807
 
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
808
 
 
809
 
                        /*
810
 
                         * Remove the entry and return an error to the client.
811
 
                         */
812
 
 
813
 
                        if (br_lck) {
814
 
                                brl_remove_pending_lock(br_lck,
815
 
                                        blr->lock_pid,
816
 
                                        procid_self(),
817
 
                                        blr->offset,
818
 
                                        blr->count,
819
 
                                        blr->lock_flav);
820
 
                                TALLOC_FREE(br_lck);
821
 
                        }
822
 
 
823
 
                        DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
824
 
                        blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
825
 
                        free_blocking_lock_record(blr);
826
 
                        change_to_root_user();
827
 
                        continue;
828
 
                }
829
 
 
830
 
                /*
831
 
                 * Go through the remaining locks and try and obtain them.
832
 
                 * The call returns True if all locks were obtained successfully
833
 
                 * and False if we still need to wait.
834
 
                 */
835
 
 
836
 
                if(blocking_lock_record_process(blr)) {
837
 
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
838
 
 
839
 
                        if (br_lck) {
840
 
                                brl_remove_pending_lock(br_lck,
841
 
                                        blr->lock_pid,
842
 
                                        procid_self(),
843
 
                                        blr->offset,
844
 
                                        blr->count,
845
 
                                        blr->lock_flav);
846
 
                                TALLOC_FREE(br_lck);
847
 
                        }
848
 
 
849
 
                        free_blocking_lock_record(blr);
850
 
                }
851
 
                change_to_root_user();
852
 
        }
853
 
}