s4-ntvfs: move valid lock range test from smb2 layer to generic code
[ira/wip.git] / source4 / torture / raw / lock.c
1 /* 
2    Unix SMB/CIFS implementation.
3    test suite for various lock operations
4    Copyright (C) Andrew Tridgell 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 "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "libcli/libcli.h"
27 #include "torture/util.h"
28 #include "libcli/composite/composite.h"
29 #include "libcli/smb_composite/smb_composite.h"
30 #include "lib/cmdline/popt_common.h"
31 #include "param/param.h"
32
33 #define CHECK_STATUS(status, correct) do { \
34         if (!NT_STATUS_EQUAL(status, correct)) { \
35                 torture_result(tctx, TORTURE_FAIL, \
36                         "(%s) Incorrect status %s - should be %s\n", \
37                         __location__, nt_errstr(status), nt_errstr(correct)); \
38                 ret = false; \
39                 goto done; \
40         }} while (0)
41
42 #define CHECK_STATUS_CONT(status, correct) do { \
43         if (!NT_STATUS_EQUAL(status, correct)) { \
44                 torture_result(tctx, TORTURE_FAIL, \
45                         "(%s) Incorrect status %s - should be %s\n", \
46                         __location__, nt_errstr(status), nt_errstr(correct)); \
47                 ret = false; \
48         }} while (0)
49
50 #define CHECK_STATUS_OR(status, correct1, correct2) do { \
51         if ((!NT_STATUS_EQUAL(status, correct1)) && \
52             (!NT_STATUS_EQUAL(status, correct2))) { \
53                 torture_result(tctx, TORTURE_FAIL, \
54                         "(%s) Incorrect status %s - should be %s or %s\n", \
55                         __location__, nt_errstr(status), nt_errstr(correct1), \
56                         nt_errstr(correct2)); \
57                 ret = false; \
58                 goto done; \
59         }} while (0)
60
61 #define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \
62         if ((!NT_STATUS_EQUAL(status, correct1)) && \
63             (!NT_STATUS_EQUAL(status, correct2))) { \
64                 torture_result(tctx, TORTURE_FAIL, \
65                         "(%s) Incorrect status %s - should be %s or %s\n", \
66                         __location__, nt_errstr(status), nt_errstr(correct1), \
67                         nt_errstr(correct2)); \
68                 ret = false; \
69         }} while (0)
70 #define BASEDIR "\\testlock"
71
72 #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
73 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
74 #define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
75
76 /*
77   test SMBlock and SMBunlock ops
78 */
79 static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
80 {
81         union smb_lock io;
82         NTSTATUS status;
83         bool ret = true;
84         int fnum;
85         const char *fname = BASEDIR "\\test.txt";
86
87         if (!torture_setup_dir(cli, BASEDIR)) {
88                 return false;
89         }
90
91         torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
92         io.generic.level = RAW_LOCK_LOCK;
93         
94         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
95         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
96                        "Failed to create %s - %s\n",
97                        fname, smbcli_errstr(cli->tree)));
98
99         torture_comment(tctx, "Trying 0/0 lock\n");
100         io.lock.level = RAW_LOCK_LOCK;
101         io.lock.in.file.fnum = fnum;
102         io.lock.in.count = 0;
103         io.lock.in.offset = 0;
104         status = smb_raw_lock(cli->tree, &io);
105         CHECK_STATUS(status, NT_STATUS_OK);
106         cli->session->pid++;
107         status = smb_raw_lock(cli->tree, &io);
108         CHECK_STATUS(status, NT_STATUS_OK);
109         cli->session->pid--;
110         io.lock.level = RAW_LOCK_UNLOCK;
111         status = smb_raw_lock(cli->tree, &io);
112         CHECK_STATUS(status, NT_STATUS_OK);
113
114         torture_comment(tctx, "Trying 0/1 lock\n");
115         io.lock.level = RAW_LOCK_LOCK;
116         io.lock.in.file.fnum = fnum;
117         io.lock.in.count = 1;
118         io.lock.in.offset = 0;
119         status = smb_raw_lock(cli->tree, &io);
120         CHECK_STATUS(status, NT_STATUS_OK);
121         cli->session->pid++;
122         status = smb_raw_lock(cli->tree, &io);
123         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
124         cli->session->pid--;
125         io.lock.level = RAW_LOCK_UNLOCK;
126         status = smb_raw_lock(cli->tree, &io);
127         CHECK_STATUS(status, NT_STATUS_OK);
128         io.lock.level = RAW_LOCK_UNLOCK;
129         status = smb_raw_lock(cli->tree, &io);
130         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
131
132         torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
133         io.lock.level = RAW_LOCK_LOCK;
134         io.lock.in.file.fnum = fnum;
135         io.lock.in.count = 4000;
136         io.lock.in.offset = 0xEEFFFFFF;
137         status = smb_raw_lock(cli->tree, &io);
138         CHECK_STATUS(status, NT_STATUS_OK);
139         cli->session->pid++;
140         status = smb_raw_lock(cli->tree, &io);
141         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
142         cli->session->pid--;
143         io.lock.level = RAW_LOCK_UNLOCK;
144         status = smb_raw_lock(cli->tree, &io);
145         CHECK_STATUS(status, NT_STATUS_OK);
146         io.lock.level = RAW_LOCK_UNLOCK;
147         status = smb_raw_lock(cli->tree, &io);
148         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
149
150         torture_comment(tctx, "Trying 0xEF000000 lock\n");
151         io.lock.level = RAW_LOCK_LOCK;
152         io.lock.in.file.fnum = fnum;
153         io.lock.in.count = 4000;
154         io.lock.in.offset = 0xEEFFFFFF;
155         status = smb_raw_lock(cli->tree, &io);
156         CHECK_STATUS(status, NT_STATUS_OK);
157         cli->session->pid++;
158         status = smb_raw_lock(cli->tree, &io);
159         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
160         cli->session->pid--;
161         io.lock.level = RAW_LOCK_UNLOCK;
162         status = smb_raw_lock(cli->tree, &io);
163         CHECK_STATUS(status, NT_STATUS_OK);
164         io.lock.level = RAW_LOCK_UNLOCK;
165         status = smb_raw_lock(cli->tree, &io);
166         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
167
168         torture_comment(tctx, "Trying max lock\n");
169         io.lock.level = RAW_LOCK_LOCK;
170         io.lock.in.file.fnum = fnum;
171         io.lock.in.count = 4000;
172         io.lock.in.offset = 0xEF000000;
173         status = smb_raw_lock(cli->tree, &io);
174         CHECK_STATUS(status, NT_STATUS_OK);
175         cli->session->pid++;
176         status = smb_raw_lock(cli->tree, &io);
177         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
178         cli->session->pid--;
179         io.lock.level = RAW_LOCK_UNLOCK;
180         status = smb_raw_lock(cli->tree, &io);
181         CHECK_STATUS(status, NT_STATUS_OK);
182         io.lock.level = RAW_LOCK_UNLOCK;
183         status = smb_raw_lock(cli->tree, &io);
184         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
185
186         torture_comment(tctx, "Trying wrong pid unlock\n");
187         io.lock.level = RAW_LOCK_LOCK;
188         io.lock.in.file.fnum = fnum;
189         io.lock.in.count = 4002;
190         io.lock.in.offset = 10001;
191         status = smb_raw_lock(cli->tree, &io);
192         CHECK_STATUS(status, NT_STATUS_OK);
193         cli->session->pid++;
194         io.lock.level = RAW_LOCK_UNLOCK;
195         status = smb_raw_lock(cli->tree, &io);
196         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
197         cli->session->pid--;
198         status = smb_raw_lock(cli->tree, &io);
199         CHECK_STATUS(status, NT_STATUS_OK);
200
201 done:
202         smbcli_close(cli->tree, fnum);
203         smb_raw_exit(cli->session);
204         smbcli_deltree(cli->tree, BASEDIR);
205         return ret;
206 }
207
208
209 /*
210   test locking&X ops
211 */
212 static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
213 {
214         union smb_lock io;
215         struct smb_lock_entry lock[1];
216         NTSTATUS status;
217         bool ret = true;
218         int fnum;
219         const char *fname = BASEDIR "\\test.txt";
220
221         if (!torture_setup_dir(cli, BASEDIR)) {
222                 return false;
223         }
224
225         torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
226         io.generic.level = RAW_LOCK_LOCKX;
227         
228         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
229         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
230                        "Failed to create %s - %s\n",
231                        fname, smbcli_errstr(cli->tree)));
232
233         io.lockx.level = RAW_LOCK_LOCKX;
234         io.lockx.in.file.fnum = fnum;
235         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
236         io.lockx.in.timeout = 0;
237         io.lockx.in.ulock_cnt = 0;
238         io.lockx.in.lock_cnt = 1;
239         lock[0].pid = cli->session->pid;
240         lock[0].offset = 10;
241         lock[0].count = 1;
242         io.lockx.in.locks = &lock[0];
243         status = smb_raw_lock(cli->tree, &io);
244         CHECK_STATUS(status, NT_STATUS_OK);
245
246
247         torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
248         io.lockx.in.ulock_cnt = 0;
249         io.lockx.in.lock_cnt = 1;
250         lock[0].count = 4000;
251         lock[0].offset = 0xEEFFFFFF;
252         status = smb_raw_lock(cli->tree, &io);
253         CHECK_STATUS(status, NT_STATUS_OK);
254         lock[0].pid++;
255         status = smb_raw_lock(cli->tree, &io);
256         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
257         lock[0].pid--;
258         io.lockx.in.ulock_cnt = 1;
259         io.lockx.in.lock_cnt = 0;
260         status = smb_raw_lock(cli->tree, &io);
261         CHECK_STATUS(status, NT_STATUS_OK);
262         status = smb_raw_lock(cli->tree, &io);
263         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
264
265         torture_comment(tctx, "Trying 0xEF000000 lock\n");
266         io.lockx.in.ulock_cnt = 0;
267         io.lockx.in.lock_cnt = 1;
268         lock[0].count = 4000;
269         lock[0].offset = 0xEF000000;
270         status = smb_raw_lock(cli->tree, &io);
271         CHECK_STATUS(status, NT_STATUS_OK);
272         lock[0].pid++;
273         status = smb_raw_lock(cli->tree, &io);
274         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
275         lock[0].pid--;
276         io.lockx.in.ulock_cnt = 1;
277         io.lockx.in.lock_cnt = 0;
278         status = smb_raw_lock(cli->tree, &io);
279         CHECK_STATUS(status, NT_STATUS_OK);
280         status = smb_raw_lock(cli->tree, &io);
281         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
282
283         torture_comment(tctx, "Trying zero lock\n");
284         io.lockx.in.ulock_cnt = 0;
285         io.lockx.in.lock_cnt = 1;
286         lock[0].count = 0;
287         lock[0].offset = ~0;
288         status = smb_raw_lock(cli->tree, &io);
289         CHECK_STATUS(status, NT_STATUS_OK);
290         lock[0].pid++;
291         status = smb_raw_lock(cli->tree, &io);
292         CHECK_STATUS(status, NT_STATUS_OK);
293         lock[0].pid--;
294         io.lockx.in.ulock_cnt = 1;
295         io.lockx.in.lock_cnt = 0;
296         status = smb_raw_lock(cli->tree, &io);
297         CHECK_STATUS(status, NT_STATUS_OK);
298         status = smb_raw_lock(cli->tree, &io);
299         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
300
301         torture_comment(tctx, "Trying max lock\n");
302         io.lockx.in.ulock_cnt = 0;
303         io.lockx.in.lock_cnt = 1;
304         lock[0].count = 0;
305         lock[0].offset = ~0;
306         status = smb_raw_lock(cli->tree, &io);
307         CHECK_STATUS(status, NT_STATUS_OK);
308         lock[0].pid++;
309         status = smb_raw_lock(cli->tree, &io);
310         CHECK_STATUS(status, NT_STATUS_OK);
311         lock[0].pid--;
312         io.lockx.in.ulock_cnt = 1;
313         io.lockx.in.lock_cnt = 0;
314         status = smb_raw_lock(cli->tree, &io);
315         CHECK_STATUS(status, NT_STATUS_OK);
316         status = smb_raw_lock(cli->tree, &io);
317         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
318
319         torture_comment(tctx, "Trying 2^63\n");
320         io.lockx.in.ulock_cnt = 0;
321         io.lockx.in.lock_cnt = 1;
322         lock[0].count = 1;
323         lock[0].offset = 1;
324         lock[0].offset <<= 63;
325         status = smb_raw_lock(cli->tree, &io);
326         CHECK_STATUS(status, NT_STATUS_OK);
327         lock[0].pid++;
328         status = smb_raw_lock(cli->tree, &io);
329         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
330         lock[0].pid--;
331         io.lockx.in.ulock_cnt = 1;
332         io.lockx.in.lock_cnt = 0;
333         status = smb_raw_lock(cli->tree, &io);
334         CHECK_STATUS(status, NT_STATUS_OK);
335         status = smb_raw_lock(cli->tree, &io);
336         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
337
338         torture_comment(tctx, "Trying 2^63 - 1\n");
339         io.lockx.in.ulock_cnt = 0;
340         io.lockx.in.lock_cnt = 1;
341         lock[0].count = 1;
342         lock[0].offset = 1;
343         lock[0].offset <<= 63;
344         lock[0].offset--;
345         status = smb_raw_lock(cli->tree, &io);
346         CHECK_STATUS(status, NT_STATUS_OK);
347         lock[0].pid++;
348         status = smb_raw_lock(cli->tree, &io);
349         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
350         lock[0].pid--;
351         io.lockx.in.ulock_cnt = 1;
352         io.lockx.in.lock_cnt = 0;
353         status = smb_raw_lock(cli->tree, &io);
354         CHECK_STATUS(status, NT_STATUS_OK);
355         status = smb_raw_lock(cli->tree, &io);
356         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
357
358         torture_comment(tctx, "Trying max lock 2\n");
359         io.lockx.in.ulock_cnt = 0;
360         io.lockx.in.lock_cnt = 1;
361         lock[0].count = 1;
362         lock[0].offset = ~0;
363         status = smb_raw_lock(cli->tree, &io);
364         CHECK_STATUS(status, NT_STATUS_OK);
365         lock[0].pid++;
366         lock[0].count = 2;
367         status = smb_raw_lock(cli->tree, &io);
368         if (TARGET_IS_WIN7(tctx))
369                 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
370         else
371                 CHECK_STATUS(status, NT_STATUS_OK);
372         lock[0].pid--;
373         io.lockx.in.ulock_cnt = 1;
374         io.lockx.in.lock_cnt = 0;
375         lock[0].count = 1;
376         status = smb_raw_lock(cli->tree, &io);
377
378         CHECK_STATUS(status, NT_STATUS_OK);
379         status = smb_raw_lock(cli->tree, &io);
380         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
381
382 done:
383         smbcli_close(cli->tree, fnum);
384         smb_raw_exit(cli->session);
385         smbcli_deltree(cli->tree, BASEDIR);
386         return ret;
387 }
388
389 /*
390   test high pid
391 */
392 static bool test_pidhigh(struct torture_context *tctx, 
393                                                  struct smbcli_state *cli)
394 {
395         union smb_lock io;
396         struct smb_lock_entry lock[1];
397         NTSTATUS status;
398         bool ret = true;
399         int fnum;
400         const char *fname = BASEDIR "\\test.txt";
401         uint8_t c = 1;
402
403         if (!torture_setup_dir(cli, BASEDIR)) {
404                 return false;
405         }
406
407         torture_comment(tctx, "Testing high pid\n");
408         io.generic.level = RAW_LOCK_LOCKX;
409
410         cli->session->pid = 1;
411         
412         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
413         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
414                        "Failed to create %s - %s\n",
415                        fname, smbcli_errstr(cli->tree)));
416
417         if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
418                 torture_result(tctx, TORTURE_FAIL,
419                         "Failed to write 1 byte - %s\n",
420                         smbcli_errstr(cli->tree));
421                 ret = false;
422                 goto done;
423         }
424
425         io.lockx.level = RAW_LOCK_LOCKX;
426         io.lockx.in.file.fnum = fnum;
427         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
428         io.lockx.in.timeout = 0;
429         io.lockx.in.ulock_cnt = 0;
430         io.lockx.in.lock_cnt = 1;
431         lock[0].pid = cli->session->pid;
432         lock[0].offset = 0;
433         lock[0].count = 0xFFFFFFFF;
434         io.lockx.in.locks = &lock[0];
435         status = smb_raw_lock(cli->tree, &io);
436         CHECK_STATUS(status, NT_STATUS_OK);
437
438         if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
439                 torture_result(tctx, TORTURE_FAIL,
440                         "Failed to read 1 byte - %s\n",
441                         smbcli_errstr(cli->tree));
442                 ret = false;
443                 goto done;
444         }
445
446         cli->session->pid = 2;
447
448         if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
449                 torture_result(tctx, TORTURE_FAIL,
450                         "pid is incorrect handled for read with lock!\n");
451                 ret = false;
452                 goto done;
453         }
454
455         cli->session->pid = 0x10001;
456
457         if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
458                 torture_result(tctx, TORTURE_FAIL,
459                         "High pid is used on this server!\n");
460                 ret = false;
461         } else {
462                 torture_warning(tctx, "High pid is not used on this server (correct)\n");
463         }
464
465 done:
466         smbcli_close(cli->tree, fnum);
467         smb_raw_exit(cli->session);
468         smbcli_deltree(cli->tree, BASEDIR);
469         return ret;
470 }
471
472
473 /*
474   test locking&X async operation
475 */
476 static bool test_async(struct torture_context *tctx, 
477                                            struct smbcli_state *cli)
478 {
479         struct smbcli_session *session;
480         struct smb_composite_sesssetup setup;
481         struct smbcli_tree *tree;
482         union smb_tcon tcon;
483         const char *host, *share;
484         union smb_lock io;
485         struct smb_lock_entry lock[2];
486         NTSTATUS status;
487         bool ret = true;
488         int fnum;
489         const char *fname = BASEDIR "\\test.txt";
490         time_t t;
491         struct smbcli_request *req;
492         struct smbcli_session_options options;
493
494         if (!torture_setup_dir(cli, BASEDIR)) {
495                 return false;
496         }
497
498         lp_smbcli_session_options(tctx->lp_ctx, &options);
499
500         torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
501         io.generic.level = RAW_LOCK_LOCKX;
502
503         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
504         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
505                        "Failed to create %s - %s\n",
506                        fname, smbcli_errstr(cli->tree)));
507
508         io.lockx.level = RAW_LOCK_LOCKX;
509         io.lockx.in.file.fnum = fnum;
510         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
511         io.lockx.in.timeout = 0;
512         io.lockx.in.ulock_cnt = 0;
513         io.lockx.in.lock_cnt = 1;
514         lock[0].pid = cli->session->pid;
515         lock[0].offset = 100;
516         lock[0].count = 10;
517         io.lockx.in.locks = &lock[0];
518         status = smb_raw_lock(cli->tree, &io);
519         CHECK_STATUS(status, NT_STATUS_OK);
520
521         t = time(NULL);
522
523         torture_comment(tctx, "testing cancel by CANCEL_LOCK\n");
524
525         /* setup a timed lock */
526         io.lockx.in.timeout = 10000;
527         req = smb_raw_lock_send(cli->tree, &io);
528         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
529                        "Failed to setup timed lock (%s)\n", __location__));
530
531         /* cancel the wrong range */
532         lock[0].offset = 0;
533         io.lockx.in.timeout = 0;
534         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
535         status = smb_raw_lock(cli->tree, &io);
536         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
537
538         /* cancel with the wrong bits set */
539         lock[0].offset = 100;
540         io.lockx.in.timeout = 0;
541         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
542         status = smb_raw_lock(cli->tree, &io);
543         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
544
545         /* cancel the right range */
546         lock[0].offset = 100;
547         io.lockx.in.timeout = 0;
548         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
549         status = smb_raw_lock(cli->tree, &io);
550         CHECK_STATUS(status, NT_STATUS_OK);
551
552         /* receive the failed lock request */
553         status = smbcli_request_simple_recv(req);
554         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
555
556         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
557                        "lock cancel was not immediate (%s)\n", __location__));
558
559         torture_comment(tctx, "testing cancel by unlock\n");
560         io.lockx.in.ulock_cnt = 0;
561         io.lockx.in.lock_cnt = 1;
562         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
563         io.lockx.in.timeout = 0;
564         status = smb_raw_lock(cli->tree, &io);
565         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
566
567         io.lockx.in.timeout = 5000;
568         req = smb_raw_lock_send(cli->tree, &io);
569         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
570                        "Failed to setup timed lock (%s)\n", __location__));
571
572         io.lockx.in.ulock_cnt = 1;
573         io.lockx.in.lock_cnt = 0;
574         status = smb_raw_lock(cli->tree, &io);
575         CHECK_STATUS(status, NT_STATUS_OK);
576
577         t = time(NULL);
578         status = smbcli_request_simple_recv(req);
579         CHECK_STATUS(status, NT_STATUS_OK);
580
581         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
582                        "lock cancel by unlock was not immediate (%s) - took %d secs\n",
583                        __location__, (int)(time(NULL)-t)));
584
585         torture_comment(tctx, "testing cancel by close\n");
586         io.lockx.in.ulock_cnt = 0;
587         io.lockx.in.lock_cnt = 1;
588         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
589         io.lockx.in.timeout = 0;
590         status = smb_raw_lock(cli->tree, &io);
591         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
592
593         t = time(NULL);
594         io.lockx.in.timeout = 10000;
595         req = smb_raw_lock_send(cli->tree, &io);
596         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
597                        "Failed to setup timed lock (%s)\n", __location__));
598
599         status = smbcli_close(cli->tree, fnum);
600         CHECK_STATUS(status, NT_STATUS_OK);
601
602         status = smbcli_request_simple_recv(req);
603         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
604
605         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
606                        "lock cancel by close was not immediate (%s)\n", __location__));
607
608         torture_comment(tctx, "create a new sessions\n");
609         session = smbcli_session_init(cli->transport, tctx, false, options);
610         setup.in.sesskey = cli->transport->negotiate.sesskey;
611         setup.in.capabilities = cli->transport->negotiate.capabilities;
612         setup.in.workgroup = lp_workgroup(tctx->lp_ctx);
613         setup.in.credentials = cmdline_credentials;
614         setup.in.gensec_settings = lp_gensec_settings(tctx, tctx->lp_ctx);
615         status = smb_composite_sesssetup(session, &setup);
616         CHECK_STATUS(status, NT_STATUS_OK);
617         session->vuid = setup.out.vuid;
618
619         torture_comment(tctx, "create new tree context\n");
620         share = torture_setting_string(tctx, "share", NULL);
621         host  = torture_setting_string(tctx, "host", NULL);
622         tree = smbcli_tree_init(session, tctx, false);
623         tcon.generic.level = RAW_TCON_TCONX;
624         tcon.tconx.in.flags = 0;
625         tcon.tconx.in.password = data_blob(NULL, 0);
626         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
627         tcon.tconx.in.device = "A:";
628         status = smb_raw_tcon(tree, tctx, &tcon);
629         CHECK_STATUS(status, NT_STATUS_OK);
630         tree->tid = tcon.tconx.out.tid;
631
632         torture_comment(tctx, "testing cancel by exit\n");
633         fname = BASEDIR "\\test_exit.txt";
634         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
635         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
636                        "Failed to reopen %s - %s\n",
637                        fname, smbcli_errstr(tree)));
638
639         io.lockx.level = RAW_LOCK_LOCKX;
640         io.lockx.in.file.fnum = fnum;
641         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
642         io.lockx.in.timeout = 0;
643         io.lockx.in.ulock_cnt = 0;
644         io.lockx.in.lock_cnt = 1;
645         lock[0].pid = session->pid;
646         lock[0].offset = 100;
647         lock[0].count = 10;
648         io.lockx.in.locks = &lock[0];
649         status = smb_raw_lock(tree, &io);
650         CHECK_STATUS(status, NT_STATUS_OK);
651
652         io.lockx.in.ulock_cnt = 0;
653         io.lockx.in.lock_cnt = 1;
654         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
655         io.lockx.in.timeout = 0;
656         status = smb_raw_lock(tree, &io);
657         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
658
659         io.lockx.in.timeout = 10000;
660         t = time(NULL);
661         req = smb_raw_lock_send(tree, &io);
662         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
663                        "Failed to setup timed lock (%s)\n", __location__));
664
665         status = smb_raw_exit(session);
666         CHECK_STATUS(status, NT_STATUS_OK);
667
668         status = smbcli_request_simple_recv(req);
669         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
670
671         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
672                        "lock cancel by exit was not immediate (%s)\n", __location__));
673
674         torture_comment(tctx, "testing cancel by ulogoff\n");
675         fname = BASEDIR "\\test_ulogoff.txt";
676         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
677         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
678                        "Failed to reopen %s - %s\n",
679                        fname, smbcli_errstr(tree)));
680
681         io.lockx.level = RAW_LOCK_LOCKX;
682         io.lockx.in.file.fnum = fnum;
683         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
684         io.lockx.in.timeout = 0;
685         io.lockx.in.ulock_cnt = 0;
686         io.lockx.in.lock_cnt = 1;
687         lock[0].pid = session->pid;
688         lock[0].offset = 100;
689         lock[0].count = 10;
690         io.lockx.in.locks = &lock[0];
691         status = smb_raw_lock(tree, &io);
692         CHECK_STATUS(status, NT_STATUS_OK);
693
694         io.lockx.in.ulock_cnt = 0;
695         io.lockx.in.lock_cnt = 1;
696         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
697         io.lockx.in.timeout = 0;
698         status = smb_raw_lock(tree, &io);
699         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
700
701         io.lockx.in.timeout = 10000;
702         t = time(NULL);
703         req = smb_raw_lock_send(tree, &io);
704         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
705                        "Failed to setup timed lock (%s)\n", __location__));
706
707         status = smb_raw_ulogoff(session);
708         CHECK_STATUS(status, NT_STATUS_OK);
709
710         status = smbcli_request_simple_recv(req);
711         if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
712                 torture_result(tctx, TORTURE_FAIL,
713                         "lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n",
714                         nt_errstr(status));
715                 smb_tree_disconnect(tree);
716                 smb_raw_exit(session);
717                 goto done;
718         }
719         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
720
721         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
722                        "lock cancel by ulogoff was not immediate (%s)\n", __location__));
723
724         torture_comment(tctx, "testing cancel by tdis\n");
725         tree->session = cli->session;
726
727         fname = BASEDIR "\\test_tdis.txt";
728         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
729         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
730                        "Failed to reopen %s - %s\n",
731                        fname, smbcli_errstr(tree)));
732
733         io.lockx.level = RAW_LOCK_LOCKX;
734         io.lockx.in.file.fnum = fnum;
735         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
736         io.lockx.in.timeout = 0;
737         io.lockx.in.ulock_cnt = 0;
738         io.lockx.in.lock_cnt = 1;
739         lock[0].pid = cli->session->pid;
740         lock[0].offset = 100;
741         lock[0].count = 10;
742         io.lockx.in.locks = &lock[0];
743         status = smb_raw_lock(tree, &io);
744         CHECK_STATUS(status, NT_STATUS_OK);
745
746         status = smb_raw_lock(tree, &io);
747         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
748
749         io.lockx.in.timeout = 10000;
750         t = time(NULL);
751         req = smb_raw_lock_send(tree, &io);
752         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
753                        "Failed to setup timed lock (%s)\n", __location__));
754
755         status = smb_tree_disconnect(tree);
756         CHECK_STATUS(status, NT_STATUS_OK);
757
758         status = smbcli_request_simple_recv(req);
759         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
760
761         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
762                        "lock cancel by tdis was not immediate (%s)\n", __location__));
763
764 done:
765         smb_raw_exit(cli->session);
766         smbcli_deltree(cli->tree, BASEDIR);
767         return ret;
768 }
769
770 /*
771   test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
772 */
773 static bool test_errorcode(struct torture_context *tctx, 
774                                                    struct smbcli_state *cli)
775 {
776         union smb_lock io;
777         union smb_open op;
778         struct smb_lock_entry lock[2];
779         NTSTATUS status;
780         bool ret = true;
781         int fnum, fnum2;
782         const char *fname;
783         struct smbcli_request *req;
784         time_t start;
785         int t;
786         int delay;
787
788         if (!torture_setup_dir(cli, BASEDIR)) {
789                 return false;
790         }
791
792         torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
793
794         torture_comment(tctx, "testing with timeout = 0\n");
795         fname = BASEDIR "\\test0.txt";
796         t = 0;
797
798         /*
799          * the first run is with t = 0,
800          * the second with t > 0 (=1)
801          */
802 next_run:
803         /* 
804          * use the DENY_DOS mode, that creates two fnum's of one low-level file handle,
805          * this demonstrates that the cache is per fnum
806          */
807         op.openx.level = RAW_OPEN_OPENX;
808         op.openx.in.fname = fname;
809         op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
810         op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS;
811         op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
812         op.openx.in.search_attrs = 0;
813         op.openx.in.file_attrs = 0;
814         op.openx.in.write_time = 0;
815         op.openx.in.size = 0;
816         op.openx.in.timeout = 0;
817
818         status = smb_raw_open(cli->tree, tctx, &op);
819         CHECK_STATUS(status, NT_STATUS_OK);
820         fnum = op.openx.out.file.fnum;
821
822         status = smb_raw_open(cli->tree, tctx, &op);
823         CHECK_STATUS(status, NT_STATUS_OK);
824         fnum2 = op.openx.out.file.fnum;
825
826         io.lockx.level = RAW_LOCK_LOCKX;
827         io.lockx.in.file.fnum = fnum;
828         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
829         io.lockx.in.timeout = t;
830         io.lockx.in.ulock_cnt = 0;
831         io.lockx.in.lock_cnt = 1;
832         lock[0].pid = cli->session->pid;
833         lock[0].offset = 100;
834         lock[0].count = 10;
835         io.lockx.in.locks = &lock[0];
836         status = smb_raw_lock(cli->tree, &io);
837         CHECK_STATUS(status, NT_STATUS_OK);
838
839         /*
840          * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
841          * this also demonstrates that the error code cache is per file handle
842          * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
843          */
844         io.lockx.in.file.fnum = fnum2;
845         status = smb_raw_lock(cli->tree, &io);
846         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
847
848         io.lockx.in.file.fnum = fnum;
849         status = smb_raw_lock(cli->tree, &io);
850         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
851
852         /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
853         io.lockx.in.file.fnum = fnum;
854         status = smb_raw_lock(cli->tree, &io);
855         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
856
857         io.lockx.in.file.fnum = fnum2;
858         status = smb_raw_lock(cli->tree, &io);
859         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
860
861         io.lockx.in.file.fnum = fnum;
862         status = smb_raw_lock(cli->tree, &io);
863         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
864
865         io.lockx.in.file.fnum = fnum2;
866         status = smb_raw_lock(cli->tree, &io);
867         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
868
869         /* demonstrate that the smbpid doesn't matter */
870         lock[0].pid++;
871         io.lockx.in.file.fnum = fnum;
872         status = smb_raw_lock(cli->tree, &io);
873         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
874
875         io.lockx.in.file.fnum = fnum2;
876         status = smb_raw_lock(cli->tree, &io);
877         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
878         lock[0].pid--;
879
880         /* 
881          * demonstrate the a successful lock with count = 0 and the same offset,
882          * doesn't reset the error cache
883          */
884         lock[0].offset = 100;
885         lock[0].count = 0;
886         io.lockx.in.file.fnum = fnum;
887         status = smb_raw_lock(cli->tree, &io);
888         CHECK_STATUS(status, NT_STATUS_OK);
889
890         io.lockx.in.file.fnum = fnum2;
891         status = smb_raw_lock(cli->tree, &io);
892         CHECK_STATUS(status, NT_STATUS_OK);
893
894         lock[0].offset = 100;
895         lock[0].count = 10;
896         io.lockx.in.file.fnum = fnum;
897         status = smb_raw_lock(cli->tree, &io);
898         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
899
900         io.lockx.in.file.fnum = fnum2;
901         status = smb_raw_lock(cli->tree, &io);
902         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
903
904         /* 
905          * demonstrate the a successful lock with count = 0 and outside the locked range,
906          * doesn't reset the error cache
907          */
908         lock[0].offset = 110;
909         lock[0].count = 0;
910         io.lockx.in.file.fnum = fnum;
911         status = smb_raw_lock(cli->tree, &io);
912         CHECK_STATUS(status, NT_STATUS_OK);
913
914         io.lockx.in.file.fnum = fnum2;
915         status = smb_raw_lock(cli->tree, &io);
916         CHECK_STATUS(status, NT_STATUS_OK);
917
918         lock[0].offset = 100;
919         lock[0].count = 10;
920         io.lockx.in.file.fnum = fnum;
921         status = smb_raw_lock(cli->tree, &io);
922         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
923
924         io.lockx.in.file.fnum = fnum2;
925         status = smb_raw_lock(cli->tree, &io);
926         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
927
928         lock[0].offset = 99;
929         lock[0].count = 0;
930         io.lockx.in.file.fnum = fnum;
931         status = smb_raw_lock(cli->tree, &io);
932         CHECK_STATUS(status, NT_STATUS_OK);
933
934         io.lockx.in.file.fnum = fnum2;
935         status = smb_raw_lock(cli->tree, &io);
936         CHECK_STATUS(status, NT_STATUS_OK);
937
938         lock[0].offset = 100;
939         lock[0].count = 10;
940         io.lockx.in.file.fnum = fnum;
941         status = smb_raw_lock(cli->tree, &io);
942         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
943
944         io.lockx.in.file.fnum = fnum2;
945         status = smb_raw_lock(cli->tree, &io);
946         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
947
948         /* demonstrate that a changing count doesn't reset the error cache */
949         lock[0].offset = 100;
950         lock[0].count = 5;
951         io.lockx.in.file.fnum = fnum;
952         status = smb_raw_lock(cli->tree, &io);
953         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
954
955         io.lockx.in.file.fnum = fnum2;
956         status = smb_raw_lock(cli->tree, &io);
957         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
958
959         lock[0].offset = 100;
960         lock[0].count = 15;
961         io.lockx.in.file.fnum = fnum;
962         status = smb_raw_lock(cli->tree, &io);
963         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
964
965         io.lockx.in.file.fnum = fnum2;
966         status = smb_raw_lock(cli->tree, &io);
967         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
968
969         /* 
970          * demonstrate the a lock with count = 0 and inside the locked range,
971          * fails and resets the error cache
972          */
973         lock[0].offset = 101;
974         lock[0].count = 0;
975         io.lockx.in.file.fnum = fnum;
976         status = smb_raw_lock(cli->tree, &io);
977         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
978         status = smb_raw_lock(cli->tree, &io);
979         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
980
981         io.lockx.in.file.fnum = fnum2;
982         status = smb_raw_lock(cli->tree, &io);
983         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
984         status = smb_raw_lock(cli->tree, &io);
985         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
986
987         lock[0].offset = 100;
988         lock[0].count = 10;
989         io.lockx.in.file.fnum = fnum;
990         status = smb_raw_lock(cli->tree, &io);
991         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
992         status = smb_raw_lock(cli->tree, &io);
993         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
994
995         io.lockx.in.file.fnum = fnum2;
996         status = smb_raw_lock(cli->tree, &io);
997         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
998         status = smb_raw_lock(cli->tree, &io);
999         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1000
1001         /* demonstrate the a changing offset, resets the error cache */
1002         lock[0].offset = 105;
1003         lock[0].count = 10;
1004         io.lockx.in.file.fnum = fnum;
1005         status = smb_raw_lock(cli->tree, &io);
1006         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1007         status = smb_raw_lock(cli->tree, &io);
1008         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1009
1010         io.lockx.in.file.fnum = fnum2;
1011         status = smb_raw_lock(cli->tree, &io);
1012         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1013         status = smb_raw_lock(cli->tree, &io);
1014         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1015
1016         lock[0].offset = 100;
1017         lock[0].count = 10;
1018         io.lockx.in.file.fnum = fnum;
1019         status = smb_raw_lock(cli->tree, &io);
1020         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1021         status = smb_raw_lock(cli->tree, &io);
1022         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1023
1024         io.lockx.in.file.fnum = fnum2;
1025         status = smb_raw_lock(cli->tree, &io);
1026         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1027         status = smb_raw_lock(cli->tree, &io);
1028         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1029
1030         lock[0].offset = 95;
1031         lock[0].count = 9;
1032         io.lockx.in.file.fnum = fnum;
1033         status = smb_raw_lock(cli->tree, &io);
1034         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1035         status = smb_raw_lock(cli->tree, &io);
1036         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1037
1038         io.lockx.in.file.fnum = fnum2;
1039         status = smb_raw_lock(cli->tree, &io);
1040         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1041         status = smb_raw_lock(cli->tree, &io);
1042         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1043
1044         lock[0].offset = 100;
1045         lock[0].count = 10;
1046         io.lockx.in.file.fnum = fnum;
1047         status = smb_raw_lock(cli->tree, &io);
1048         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1049         status = smb_raw_lock(cli->tree, &io);
1050         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1051
1052         io.lockx.in.file.fnum = fnum2;
1053         status = smb_raw_lock(cli->tree, &io);
1054         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1055         status = smb_raw_lock(cli->tree, &io);
1056         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1057
1058         /* 
1059          * demonstrate the a successful lock in a different range, 
1060          * doesn't reset the cache, the failing lock on the 2nd handle
1061          * resets the resets the cache
1062          */
1063         lock[0].offset = 120;
1064         lock[0].count = 15;
1065         io.lockx.in.file.fnum = fnum;
1066         status = smb_raw_lock(cli->tree, &io);
1067         CHECK_STATUS(status, NT_STATUS_OK);
1068
1069         io.lockx.in.file.fnum = fnum2;
1070         status = smb_raw_lock(cli->tree, &io);
1071         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1072
1073         lock[0].offset = 100;
1074         lock[0].count = 10;
1075         io.lockx.in.file.fnum = fnum;
1076         status = smb_raw_lock(cli->tree, &io);
1077         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1078         status = smb_raw_lock(cli->tree, &io);
1079         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1080
1081         io.lockx.in.file.fnum = fnum2;
1082         status = smb_raw_lock(cli->tree, &io);
1083         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1084         status = smb_raw_lock(cli->tree, &io);
1085         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1086
1087         /* end of the loop */
1088         if (t == 0) {
1089                 smb_raw_exit(cli->session);
1090                 t = 1;
1091                 torture_comment(tctx, "testing with timeout > 0 (=%d)\n",
1092                                 t);
1093                 fname = BASEDIR "\\test1.txt";
1094                 goto next_run;
1095         }
1096
1097         t = 4000;
1098         torture_comment(tctx, "testing special cases with timeout > 0 (=%d)\n",
1099                         t);
1100
1101         /*
1102          * the following 3 test sections demonstrate that
1103          * the cache is only set when the error is reported
1104          * to the client (after the timeout went by)
1105          */
1106         smb_raw_exit(cli->session);
1107         torture_comment(tctx, "testing a conflict while a lock is pending\n");
1108         fname = BASEDIR "\\test2.txt";
1109         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1110         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1111                        "Failed to reopen %s - %s\n",
1112                        fname, smbcli_errstr(cli->tree)));
1113
1114         io.lockx.level = RAW_LOCK_LOCKX;
1115         io.lockx.in.file.fnum = fnum;
1116         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1117         io.lockx.in.timeout = 0;
1118         io.lockx.in.ulock_cnt = 0;
1119         io.lockx.in.lock_cnt = 1;
1120         lock[0].pid = cli->session->pid;
1121         lock[0].offset = 100;
1122         lock[0].count = 10;
1123         io.lockx.in.locks = &lock[0];
1124         status = smb_raw_lock(cli->tree, &io);
1125         CHECK_STATUS(status, NT_STATUS_OK);
1126
1127         start = time(NULL);
1128         io.lockx.in.timeout = t;
1129         req = smb_raw_lock_send(cli->tree, &io);
1130         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1131                        "Failed to setup timed lock (%s)\n", __location__));
1132
1133         io.lockx.in.timeout = 0;
1134         lock[0].offset = 105;
1135         lock[0].count = 10;
1136         status = smb_raw_lock(cli->tree, &io);
1137         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1138
1139         status = smbcli_request_simple_recv(req);
1140         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1141
1142         delay = t / 1000;
1143         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1144                 delay /= 2;
1145         }
1146
1147         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1148                        "lock comes back to early timeout[%d] delay[%d]"
1149                        "(%s)\n", t, delay, __location__));
1150
1151         status = smb_raw_lock(cli->tree, &io);
1152         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1153
1154         smbcli_close(cli->tree, fnum);
1155         fname = BASEDIR "\\test3.txt";
1156         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1157         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1158                        "Failed to reopen %s - %s\n",
1159                        fname, smbcli_errstr(cli->tree)));
1160
1161         io.lockx.level = RAW_LOCK_LOCKX;
1162         io.lockx.in.file.fnum = fnum;
1163         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1164         io.lockx.in.timeout = 0;
1165         io.lockx.in.ulock_cnt = 0;
1166         io.lockx.in.lock_cnt = 1;
1167         lock[0].pid = cli->session->pid;
1168         lock[0].offset = 100;
1169         lock[0].count = 10;
1170         io.lockx.in.locks = &lock[0];
1171         status = smb_raw_lock(cli->tree, &io);
1172         CHECK_STATUS(status, NT_STATUS_OK);
1173
1174         start = time(NULL);
1175         io.lockx.in.timeout = t;
1176         req = smb_raw_lock_send(cli->tree, &io);
1177         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1178                        "Failed to setup timed lock (%s)\n", __location__));
1179
1180         io.lockx.in.timeout = 0;
1181         lock[0].offset = 105;
1182         lock[0].count = 10;
1183         status = smb_raw_lock(cli->tree, &io);
1184         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1185
1186         status = smbcli_request_simple_recv(req);
1187         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1188
1189         delay = t / 1000;
1190         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1191                 delay /= 2;
1192         }
1193
1194         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1195                        "lock comes back to early timeout[%d] delay[%d]"
1196                        "(%s)\n", t, delay, __location__));
1197
1198         lock[0].offset = 100;
1199         lock[0].count = 10;
1200         status = smb_raw_lock(cli->tree, &io);
1201         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1202
1203         smbcli_close(cli->tree, fnum);
1204         fname = BASEDIR "\\test4.txt";
1205         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1206         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1207                        "Failed to reopen %s - %s\n",
1208                        fname, smbcli_errstr(cli->tree)));
1209
1210         io.lockx.level = RAW_LOCK_LOCKX;
1211         io.lockx.in.file.fnum = fnum;
1212         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1213         io.lockx.in.timeout = 0;
1214         io.lockx.in.ulock_cnt = 0;
1215         io.lockx.in.lock_cnt = 1;
1216         lock[0].pid = cli->session->pid;
1217         lock[0].offset = 100;
1218         lock[0].count = 10;
1219         io.lockx.in.locks = &lock[0];
1220         status = smb_raw_lock(cli->tree, &io);
1221         CHECK_STATUS(status, NT_STATUS_OK);
1222
1223         start = time(NULL);
1224         io.lockx.in.timeout = t;
1225         req = smb_raw_lock_send(cli->tree, &io);
1226         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1227                        "Failed to setup timed lock (%s)\n", __location__));
1228
1229         io.lockx.in.timeout = 0;
1230         status = smb_raw_lock(cli->tree, &io);
1231         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1232
1233         status = smbcli_request_simple_recv(req);
1234         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1235
1236         delay = t / 1000;
1237         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1238                 delay /= 2;
1239         }
1240
1241         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1242                        "lock comes back to early timeout[%d] delay[%d]"
1243                        "(%s)\n", t, delay, __location__));
1244
1245         status = smb_raw_lock(cli->tree, &io);
1246         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1247
1248 done:
1249         smb_raw_exit(cli->session);
1250         smbcli_deltree(cli->tree, BASEDIR);
1251         return ret;
1252 }
1253
1254
1255 /*
1256   test LOCKING_ANDX_CHANGE_LOCKTYPE
1257 */
1258 static bool test_changetype(struct torture_context *tctx, 
1259                                                         struct smbcli_state *cli)
1260 {
1261         union smb_lock io;
1262         struct smb_lock_entry lock[2];
1263         NTSTATUS status;
1264         bool ret = true;
1265         int fnum;
1266         uint8_t c = 0;
1267         const char *fname = BASEDIR "\\test.txt";
1268
1269         if (!torture_setup_dir(cli, BASEDIR)) {
1270                 return false;
1271         }
1272
1273         torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1274         io.generic.level = RAW_LOCK_LOCKX;
1275         
1276         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1277         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1278                        "Failed to create %s - %s\n",
1279                        fname, smbcli_errstr(cli->tree)));
1280
1281         io.lockx.level = RAW_LOCK_LOCKX;
1282         io.lockx.in.file.fnum = fnum;
1283         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1284         io.lockx.in.timeout = 0;
1285         io.lockx.in.ulock_cnt = 0;
1286         io.lockx.in.lock_cnt = 1;
1287         lock[0].pid = cli->session->pid;
1288         lock[0].offset = 100;
1289         lock[0].count = 10;
1290         io.lockx.in.locks = &lock[0];
1291         status = smb_raw_lock(cli->tree, &io);
1292         CHECK_STATUS(status, NT_STATUS_OK);
1293
1294         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1295                 torture_result(tctx, TORTURE_FAIL,
1296                         "allowed write on read locked region (%s)\n", __location__);
1297                 ret = false;
1298                 goto done;
1299         }
1300
1301         /* windows server don't seem to support this */
1302         io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1303         status = smb_raw_lock(cli->tree, &io);
1304         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1305
1306         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1307                 torture_result(tctx, TORTURE_FAIL,
1308                         "allowed write after lock change (%s)\n", __location__);
1309                 ret = false;
1310                 goto done;
1311         }
1312
1313 done:
1314         smbcli_close(cli->tree, fnum);
1315         smb_raw_exit(cli->session);
1316         smbcli_deltree(cli->tree, BASEDIR);
1317         return ret;
1318 }
1319
1320 struct double_lock_test {
1321         struct smb_lock_entry lock1;
1322         struct smb_lock_entry lock2;
1323         NTSTATUS exp_status;
1324 };
1325
1326 /**
1327  * Tests zero byte locks.
1328  */
1329 static const struct double_lock_test zero_byte_tests[] = {
1330         /* {pid, offset, count}, {pid, offset, count}, status */
1331
1332         /** First, takes a zero byte lock at offset 10. Then:
1333         *   - Taking 0 byte lock at 10 should succeed.
1334         *   - Taking 1 byte locks at 9,10,11 should succeed.
1335         *   - Taking 2 byte lock at 9 should fail.
1336         *   - Taking 2 byte lock at 10 should succeed.
1337         *   - Taking 3 byte lock at 9 should fail.
1338         */
1339         {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1340         {{1000, 10, 0}, {1001, 9, 1},  NT_STATUS_OK},
1341         {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1342         {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1343         {{1000, 10, 0}, {1001, 9, 2},  NT_STATUS_LOCK_NOT_GRANTED},
1344         {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1345         {{1000, 10, 0}, {1001, 9, 3},  NT_STATUS_LOCK_NOT_GRANTED},
1346
1347         /** Same, but opposite order. */
1348         {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1349         {{1001, 9, 1},  {1000, 10, 0}, NT_STATUS_OK},
1350         {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1351         {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1352         {{1001, 9, 2},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1353         {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1354         {{1001, 9, 3},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1355
1356         /** Zero zero case. */
1357         {{1000, 0, 0},  {1001, 0, 0},  NT_STATUS_OK},
1358 };
1359
1360 static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1361 {
1362         union smb_lock io;
1363         NTSTATUS status;
1364         bool ret = true;
1365         int fnum, i;
1366         const char *fname = BASEDIR "\\zero.txt";
1367
1368         torture_comment(tctx, "Testing zero length byte range locks:\n");
1369
1370         if (!torture_setup_dir(cli, BASEDIR)) {
1371                 return false;
1372         }
1373
1374         io.generic.level = RAW_LOCK_LOCKX;
1375
1376         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1377         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1378                        "Failed to create %s - %s\n",
1379                        fname, smbcli_errstr(cli->tree)));
1380
1381         /* Setup initial parameters */
1382         io.lockx.level = RAW_LOCK_LOCKX;
1383         io.lockx.in.file.fnum = fnum;
1384         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1385         io.lockx.in.timeout = 0;
1386
1387         /* Try every combination of locks in zero_byte_tests. The first lock is
1388          * assumed to succeed. The second lock may contend, depending on the
1389          * expected status. */
1390         for (i = 0;
1391              i < ARRAY_SIZE(zero_byte_tests);
1392              i++) {
1393                 torture_comment(tctx, "  ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1394                     zero_byte_tests[i].lock1.pid,
1395                     zero_byte_tests[i].lock1.offset,
1396                     zero_byte_tests[i].lock1.count,
1397                     zero_byte_tests[i].lock2.pid,
1398                     zero_byte_tests[i].lock2.offset,
1399                     zero_byte_tests[i].lock2.count,
1400                     nt_errstr(zero_byte_tests[i].exp_status));
1401
1402                 /* Lock both locks. */
1403                 io.lockx.in.ulock_cnt = 0;
1404                 io.lockx.in.lock_cnt = 1;
1405
1406                 io.lockx.in.locks = &zero_byte_tests[i].lock1;
1407                 status = smb_raw_lock(cli->tree, &io);
1408                 CHECK_STATUS(status, NT_STATUS_OK);
1409
1410                 io.lockx.in.locks = &zero_byte_tests[i].lock2;
1411                 status = smb_raw_lock(cli->tree, &io);
1412
1413                 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1414                         NT_STATUS_LOCK_NOT_GRANTED)) {
1415                         /* Allow either of the failure messages and keep going
1416                          * if we see the wrong status. */
1417                         CHECK_STATUS_OR_CONT(status,
1418                             NT_STATUS_LOCK_NOT_GRANTED,
1419                             NT_STATUS_FILE_LOCK_CONFLICT);
1420
1421                 } else {
1422                         CHECK_STATUS_CONT(status,
1423                             zero_byte_tests[i].exp_status);
1424                 }
1425
1426                 /* Unlock both locks. */
1427                 io.lockx.in.ulock_cnt = 1;
1428                 io.lockx.in.lock_cnt = 0;
1429
1430                 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1431                         status = smb_raw_lock(cli->tree, &io);
1432                         CHECK_STATUS(status, NT_STATUS_OK);
1433                 }
1434
1435                 io.lockx.in.locks = &zero_byte_tests[i].lock1;
1436                 status = smb_raw_lock(cli->tree, &io);
1437                 CHECK_STATUS(status, NT_STATUS_OK);
1438         }
1439
1440 done:
1441         smbcli_close(cli->tree, fnum);
1442         smb_raw_exit(cli->session);
1443         smbcli_deltree(cli->tree, BASEDIR);
1444         return ret;
1445 }
1446
1447 static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1448 {
1449         union smb_lock io;
1450         NTSTATUS status;
1451         bool ret = true;
1452         int fnum1, fnum2;
1453         const char *fname = BASEDIR "\\unlock.txt";
1454         struct smb_lock_entry lock1;
1455         struct smb_lock_entry lock2;
1456
1457         torture_comment(tctx, "Testing LOCKX unlock:\n");
1458
1459         if (!torture_setup_dir(cli, BASEDIR)) {
1460                 return false;
1461         }
1462
1463         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1464         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1465                        "Failed to create %s - %s\n",
1466                        fname, smbcli_errstr(cli->tree)));
1467
1468         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1469         torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1470                        "Failed to create %s - %s\n",
1471                        fname, smbcli_errstr(cli->tree)));
1472
1473         /* Setup initial parameters */
1474         io.lockx.level = RAW_LOCK_LOCKX;
1475         io.lockx.in.timeout = 0;
1476
1477         lock1.pid = cli->session->pid;
1478         lock1.offset = 0;
1479         lock1.count = 10;
1480         lock2.pid = cli->session->pid - 1;
1481         lock2.offset = 0;
1482         lock2.count = 10;
1483
1484         /**
1485          * Take exclusive lock, then unlock it with a shared-unlock call.
1486          */
1487         torture_comment(tctx, "  taking exclusive lock.\n");
1488         io.lockx.in.ulock_cnt = 0;
1489         io.lockx.in.lock_cnt = 1;
1490         io.lockx.in.mode = 0;
1491         io.lockx.in.file.fnum = fnum1;
1492         io.lockx.in.locks = &lock1;
1493         status = smb_raw_lock(cli->tree, &io);
1494         CHECK_STATUS(status, NT_STATUS_OK);
1495
1496         torture_comment(tctx, "  unlock the exclusive with a shared unlock call.\n");
1497         io.lockx.in.ulock_cnt = 1;
1498         io.lockx.in.lock_cnt = 0;
1499         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1500         io.lockx.in.file.fnum = fnum1;
1501         io.lockx.in.locks = &lock1;
1502         status = smb_raw_lock(cli->tree, &io);
1503         CHECK_STATUS(status, NT_STATUS_OK);
1504
1505         torture_comment(tctx, "  try shared lock on pid2/fnum2, testing the unlock.\n");
1506         io.lockx.in.ulock_cnt = 0;
1507         io.lockx.in.lock_cnt = 1;
1508         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1509         io.lockx.in.file.fnum = fnum2;
1510         io.lockx.in.locks = &lock2;
1511         status = smb_raw_lock(cli->tree, &io);
1512         CHECK_STATUS(status, NT_STATUS_OK);
1513
1514         /**
1515          * Unlock a shared lock with an exclusive-unlock call.
1516          */
1517         torture_comment(tctx, "  unlock new shared lock with exclusive unlock call.\n");
1518         io.lockx.in.ulock_cnt = 1;
1519         io.lockx.in.lock_cnt = 0;
1520         io.lockx.in.mode = 0;
1521         io.lockx.in.file.fnum = fnum2;
1522         io.lockx.in.locks = &lock2;
1523         status = smb_raw_lock(cli->tree, &io);
1524         CHECK_STATUS(status, NT_STATUS_OK);
1525
1526         torture_comment(tctx, "  try exclusive lock on pid1, testing the unlock.\n");
1527         io.lockx.in.ulock_cnt = 0;
1528         io.lockx.in.lock_cnt = 1;
1529         io.lockx.in.mode = 0;
1530         io.lockx.in.file.fnum = fnum1;
1531         io.lockx.in.locks = &lock1;
1532         status = smb_raw_lock(cli->tree, &io);
1533         CHECK_STATUS(status, NT_STATUS_OK);
1534
1535         /* cleanup */
1536         io.lockx.in.ulock_cnt = 1;
1537         io.lockx.in.lock_cnt = 0;
1538         status = smb_raw_lock(cli->tree, &io);
1539         CHECK_STATUS(status, NT_STATUS_OK);
1540
1541         /**
1542          * Test unlocking of 0-byte locks.
1543          */
1544
1545         torture_comment(tctx, "  lock shared and exclusive 0-byte locks, testing that Windows "
1546             "always unlocks the exclusive first.\n");
1547         lock1.pid = cli->session->pid;
1548         lock1.offset = 10;
1549         lock1.count = 0;
1550         lock2.pid = cli->session->pid;
1551         lock2.offset = 5;
1552         lock2.count = 10;
1553         io.lockx.in.ulock_cnt = 0;
1554         io.lockx.in.lock_cnt = 1;
1555         io.lockx.in.file.fnum = fnum1;
1556         io.lockx.in.locks = &lock1;
1557
1558         /* lock 0-byte shared
1559          * Note: Order of the shared/exclusive locks doesn't matter. */
1560         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1561         status = smb_raw_lock(cli->tree, &io);
1562         CHECK_STATUS(status, NT_STATUS_OK);
1563
1564         /* lock 0-byte exclusive */
1565         io.lockx.in.mode = 0;
1566         status = smb_raw_lock(cli->tree, &io);
1567         CHECK_STATUS(status, NT_STATUS_OK);
1568
1569         /* test contention */
1570         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1571         io.lockx.in.locks = &lock2;
1572         io.lockx.in.file.fnum = fnum2;
1573         status = smb_raw_lock(cli->tree, &io);
1574         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1575             NT_STATUS_FILE_LOCK_CONFLICT);
1576
1577         /* unlock */
1578         io.lockx.in.ulock_cnt = 1;
1579         io.lockx.in.lock_cnt = 0;
1580         io.lockx.in.file.fnum = fnum1;
1581         io.lockx.in.locks = &lock1;
1582         status = smb_raw_lock(cli->tree, &io);
1583         CHECK_STATUS(status, NT_STATUS_OK);
1584
1585         /* test - can we take a shared lock? */
1586         io.lockx.in.ulock_cnt = 0;
1587         io.lockx.in.lock_cnt = 1;
1588         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1589         io.lockx.in.file.fnum = fnum2;
1590         io.lockx.in.locks = &lock2;
1591         status = smb_raw_lock(cli->tree, &io);
1592
1593         /* XXX Samba 3 will fail this test. This is temporary(because this isn't
1594          * new to Win7, it succeeds in WinXP too), until I can come to a
1595          * resolution as to whether Samba should support this or not. There is
1596          * code to preference unlocking exclusive locks before shared locks,
1597          * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1598         if (TARGET_IS_SAMBA3(tctx)) {
1599                 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1600                     NT_STATUS_FILE_LOCK_CONFLICT);
1601         } else {
1602                 CHECK_STATUS(status, NT_STATUS_OK);
1603         }
1604
1605         /* cleanup */
1606         io.lockx.in.ulock_cnt = 1;
1607         io.lockx.in.lock_cnt = 0;
1608         status = smb_raw_lock(cli->tree, &io);
1609
1610         /* XXX Same as above. */
1611         if (TARGET_IS_SAMBA3(tctx)) {
1612                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1613         } else {
1614                 CHECK_STATUS(status, NT_STATUS_OK);
1615         }
1616
1617         io.lockx.in.file.fnum = fnum1;
1618         io.lockx.in.locks = &lock1;
1619         status = smb_raw_lock(cli->tree, &io);
1620         CHECK_STATUS(status, NT_STATUS_OK);
1621
1622 done:
1623         smbcli_close(cli->tree, fnum1);
1624         smbcli_close(cli->tree, fnum2);
1625         smb_raw_exit(cli->session);
1626         smbcli_deltree(cli->tree, BASEDIR);
1627         return ret;
1628 }
1629
1630 static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1631 {
1632         union smb_lock io;
1633         NTSTATUS status;
1634         bool ret = true;
1635         int fnum1;
1636         const char *fname = BASEDIR "\\unlock_multiple.txt";
1637         struct smb_lock_entry lock1;
1638         struct smb_lock_entry lock2;
1639         struct smb_lock_entry locks[2];
1640
1641         torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1642
1643         if (!torture_setup_dir(cli, BASEDIR)) {
1644                 return false;
1645         }
1646
1647         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1648         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1649                        "Failed to create %s - %s\n",
1650                        fname, smbcli_errstr(cli->tree)));
1651
1652         /* Setup initial parameters */
1653         io.lockx.level = RAW_LOCK_LOCKX;
1654         io.lockx.in.timeout = 0;
1655
1656         lock1.pid = cli->session->pid;
1657         lock1.offset = 0;
1658         lock1.count = 10;
1659         lock2.pid = cli->session->pid;
1660         lock2.offset = 10;
1661         lock2.count = 10;
1662
1663         locks[0] = lock1;
1664         locks[1] = lock2;
1665
1666         io.lockx.in.file.fnum = fnum1;
1667         io.lockx.in.mode = 0; /* exclusive */
1668
1669         /** Test1: Take second lock, but not first. */
1670         torture_comment(tctx, "  unlock 2 locks, first one not locked. Expect no locks "
1671             "unlocked. \n");
1672
1673         io.lockx.in.ulock_cnt = 0;
1674         io.lockx.in.lock_cnt = 1;
1675         io.lockx.in.locks = &lock2;
1676         status = smb_raw_lock(cli->tree, &io);
1677         CHECK_STATUS(status, NT_STATUS_OK);
1678
1679         /* Try to unlock both locks. */
1680         io.lockx.in.ulock_cnt = 2;
1681         io.lockx.in.lock_cnt = 0;
1682         io.lockx.in.locks = locks;
1683
1684         status = smb_raw_lock(cli->tree, &io);
1685         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1686
1687         /* Second lock should not be unlocked. */
1688         io.lockx.in.ulock_cnt = 0;
1689         io.lockx.in.lock_cnt = 1;
1690         io.lockx.in.locks = &lock2;
1691         status = smb_raw_lock(cli->tree, &io);
1692         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1693
1694         /* cleanup */
1695         io.lockx.in.ulock_cnt = 1;
1696         io.lockx.in.lock_cnt = 0;
1697         io.lockx.in.locks = &lock2;
1698         status = smb_raw_lock(cli->tree, &io);
1699         CHECK_STATUS(status, NT_STATUS_OK);
1700
1701         /** Test2: Take first lock, but not second. */
1702         torture_comment(tctx, "  unlock 2 locks, second one not locked. Expect first lock "
1703             "unlocked.\n");
1704
1705         io.lockx.in.ulock_cnt = 0;
1706         io.lockx.in.lock_cnt = 1;
1707         io.lockx.in.locks = &lock1;
1708         status = smb_raw_lock(cli->tree, &io);
1709         CHECK_STATUS(status, NT_STATUS_OK);
1710
1711         /* Try to unlock both locks. */
1712         io.lockx.in.ulock_cnt = 2;
1713         io.lockx.in.lock_cnt = 0;
1714         io.lockx.in.locks = locks;
1715
1716         status = smb_raw_lock(cli->tree, &io);
1717         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1718
1719         /* First lock should be unlocked. */
1720         io.lockx.in.ulock_cnt = 0;
1721         io.lockx.in.lock_cnt = 1;
1722         io.lockx.in.locks = &lock1;
1723         status = smb_raw_lock(cli->tree, &io);
1724         CHECK_STATUS(status, NT_STATUS_OK);
1725
1726         /* cleanup */
1727         io.lockx.in.ulock_cnt = 1;
1728         io.lockx.in.lock_cnt = 0;
1729         io.lockx.in.locks = &lock1;
1730         status = smb_raw_lock(cli->tree, &io);
1731         CHECK_STATUS(status, NT_STATUS_OK);
1732
1733 done:
1734         smbcli_close(cli->tree, fnum1);
1735         smb_raw_exit(cli->session);
1736         smbcli_deltree(cli->tree, BASEDIR);
1737         return ret;
1738 }
1739
1740 /**
1741  * torture_locktest5 covers stacking pretty well, but its missing two tests:
1742  * - stacking an exclusive on top of shared fails
1743  * - stacking two exclusives fail
1744  */
1745 static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
1746 {
1747         union smb_lock io;
1748         NTSTATUS status;
1749         bool ret = true;
1750         int fnum1;
1751         const char *fname = BASEDIR "\\stacking.txt";
1752         struct smb_lock_entry lock1;
1753         struct smb_lock_entry lock2;
1754
1755         torture_comment(tctx, "Testing stacking:\n");
1756
1757         if (!torture_setup_dir(cli, BASEDIR)) {
1758                 return false;
1759         }
1760
1761         io.generic.level = RAW_LOCK_LOCKX;
1762
1763         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1764         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1765                        "Failed to create %s - %s\n",
1766                        fname, smbcli_errstr(cli->tree)));
1767
1768         /* Setup initial parameters */
1769         io.lockx.level = RAW_LOCK_LOCKX;
1770         io.lockx.in.timeout = 0;
1771
1772         lock1.pid = cli->session->pid;
1773         lock1.offset = 0;
1774         lock1.count = 10;
1775         lock2.pid = cli->session->pid - 1;
1776         lock2.offset = 0;
1777         lock2.count = 10;
1778
1779         /**
1780          * Try to take a shared lock, then stack an exclusive.
1781          */
1782         torture_comment(tctx, "  stacking an exclusive on top of a shared lock fails.\n");
1783         io.lockx.in.file.fnum = fnum1;
1784         io.lockx.in.locks = &lock1;
1785
1786         io.lockx.in.ulock_cnt = 0;
1787         io.lockx.in.lock_cnt = 1;
1788         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1789         status = smb_raw_lock(cli->tree, &io);
1790         CHECK_STATUS(status, NT_STATUS_OK);
1791
1792         io.lockx.in.ulock_cnt = 0;
1793         io.lockx.in.lock_cnt = 1;
1794         io.lockx.in.mode = 0;
1795         status = smb_raw_lock(cli->tree, &io);
1796         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1797             NT_STATUS_FILE_LOCK_CONFLICT);
1798
1799         /* cleanup */
1800         io.lockx.in.ulock_cnt = 1;
1801         io.lockx.in.lock_cnt = 0;
1802         status = smb_raw_lock(cli->tree, &io);
1803         CHECK_STATUS(status, NT_STATUS_OK);
1804
1805         /**
1806          * Prove that two exclusive locks do not stack.
1807          */
1808         torture_comment(tctx, "  two exclusive locks do not stack.\n");
1809         io.lockx.in.ulock_cnt = 0;
1810         io.lockx.in.lock_cnt = 1;
1811         io.lockx.in.mode = 0;
1812         status = smb_raw_lock(cli->tree, &io);
1813         CHECK_STATUS(status, NT_STATUS_OK);
1814         status = smb_raw_lock(cli->tree, &io);
1815         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1816             NT_STATUS_FILE_LOCK_CONFLICT);
1817
1818         /* cleanup */
1819         io.lockx.in.ulock_cnt = 1;
1820         io.lockx.in.lock_cnt = 0;
1821         status = smb_raw_lock(cli->tree, &io);
1822         CHECK_STATUS(status, NT_STATUS_OK);
1823
1824 done:
1825         smbcli_close(cli->tree, fnum1);
1826         smb_raw_exit(cli->session);
1827         smbcli_deltree(cli->tree, BASEDIR);
1828         return ret;
1829 }
1830
1831 /* 
1832    basic testing of lock calls
1833 */
1834 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
1835 {
1836         struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
1837
1838         torture_suite_add_1smb_test(suite, "lockx", test_lockx);
1839         torture_suite_add_1smb_test(suite, "lock", test_lock);
1840         torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
1841         torture_suite_add_1smb_test(suite, "async", test_async);
1842         torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
1843         torture_suite_add_1smb_test(suite, "changetype", test_changetype);
1844
1845         torture_suite_add_1smb_test(suite, "stacking", test_stacking);
1846         torture_suite_add_1smb_test(suite, "unlock", test_unlock);
1847         torture_suite_add_1smb_test(suite, "multiple_unlock",
1848             test_multiple_unlock);
1849         torture_suite_add_1smb_test(suite, "zerobytelocks",
1850             test_zerobytelocks);
1851
1852         return suite;
1853 }