Merge branch 'master' of git://git.samba.org/samba
[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_WINDOWS(_tctx) \
75         ((torture_setting_bool(_tctx, "w2k3", false)) || \
76          (torture_setting_bool(_tctx, "w2k8", false)) || \
77          (torture_setting_bool(_tctx, "win7", false)))
78 #define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
79 #define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false))
80
81 #define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
82         (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
83 #define TARGET_SUPPORTS_SMBEXIT(_tctx) \
84     (torture_setting_bool(_tctx, "smbexit_pdu_support", true))
85 #define TARGET_SUPPORTS_SMBLOCK(_tctx) \
86     (torture_setting_bool(_tctx, "smblock_pdu_support", true))
87 #define TARGET_SUPPORTS_OPENX_DENY_DOS(_tctx) \
88     (torture_setting_bool(_tctx, "openx_deny_dos_support", true))
89 #define TARGET_RETURNS_RANGE_NOT_LOCKED(_tctx) \
90     (torture_setting_bool(_tctx, "range_not_locked_on_file_close", true))
91 /*
92   test SMBlock and SMBunlock ops
93 */
94 static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
95 {
96         union smb_lock io;
97         NTSTATUS status;
98         bool ret = true;
99         int fnum;
100         const char *fname = BASEDIR "\\test.txt";
101
102         if (!TARGET_SUPPORTS_SMBLOCK(tctx))
103                 torture_skip(tctx, "Target does not support the SMBlock PDU");
104
105         if (!torture_setup_dir(cli, BASEDIR)) {
106                 return false;
107         }
108
109         torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
110         io.generic.level = RAW_LOCK_LOCK;
111         
112         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
113         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
114                        "Failed to create %s - %s\n",
115                        fname, smbcli_errstr(cli->tree)));
116
117         torture_comment(tctx, "Trying 0/0 lock\n");
118         io.lock.level = RAW_LOCK_LOCK;
119         io.lock.in.file.fnum = fnum;
120         io.lock.in.count = 0;
121         io.lock.in.offset = 0;
122         status = smb_raw_lock(cli->tree, &io);
123         CHECK_STATUS(status, NT_STATUS_OK);
124         cli->session->pid++;
125         status = smb_raw_lock(cli->tree, &io);
126         CHECK_STATUS(status, NT_STATUS_OK);
127         cli->session->pid--;
128         io.lock.level = RAW_LOCK_UNLOCK;
129         status = smb_raw_lock(cli->tree, &io);
130         CHECK_STATUS(status, NT_STATUS_OK);
131
132         torture_comment(tctx, "Trying 0/1 lock\n");
133         io.lock.level = RAW_LOCK_LOCK;
134         io.lock.in.file.fnum = fnum;
135         io.lock.in.count = 1;
136         io.lock.in.offset = 0;
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 0xEEFFFFFF 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_LOCK_NOT_GRANTED);
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 0xEF000000 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 = 0xEEFFFFFF;
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 max lock\n");
187         io.lock.level = RAW_LOCK_LOCK;
188         io.lock.in.file.fnum = fnum;
189         io.lock.in.count = 4000;
190         io.lock.in.offset = 0xEF000000;
191         status = smb_raw_lock(cli->tree, &io);
192         CHECK_STATUS(status, NT_STATUS_OK);
193         cli->session->pid++;
194         status = smb_raw_lock(cli->tree, &io);
195         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
196         cli->session->pid--;
197         io.lock.level = RAW_LOCK_UNLOCK;
198         status = smb_raw_lock(cli->tree, &io);
199         CHECK_STATUS(status, NT_STATUS_OK);
200         io.lock.level = RAW_LOCK_UNLOCK;
201         status = smb_raw_lock(cli->tree, &io);
202         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
203
204         torture_comment(tctx, "Trying wrong pid unlock\n");
205         io.lock.level = RAW_LOCK_LOCK;
206         io.lock.in.file.fnum = fnum;
207         io.lock.in.count = 4002;
208         io.lock.in.offset = 10001;
209         status = smb_raw_lock(cli->tree, &io);
210         CHECK_STATUS(status, NT_STATUS_OK);
211         cli->session->pid++;
212         io.lock.level = RAW_LOCK_UNLOCK;
213         status = smb_raw_lock(cli->tree, &io);
214         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
215         cli->session->pid--;
216         status = smb_raw_lock(cli->tree, &io);
217         CHECK_STATUS(status, NT_STATUS_OK);
218
219 done:
220         smbcli_close(cli->tree, fnum);
221         smb_raw_exit(cli->session);
222         smbcli_deltree(cli->tree, BASEDIR);
223         return ret;
224 }
225
226
227 /*
228   test locking&X ops
229 */
230 static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
231 {
232         union smb_lock io;
233         struct smb_lock_entry lock[1];
234         NTSTATUS status;
235         bool ret = true;
236         int fnum;
237         const char *fname = BASEDIR "\\test.txt";
238
239         if (!torture_setup_dir(cli, BASEDIR)) {
240                 return false;
241         }
242
243         torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
244         io.generic.level = RAW_LOCK_LOCKX;
245         
246         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
247         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
248                        "Failed to create %s - %s\n",
249                        fname, smbcli_errstr(cli->tree)));
250
251         io.lockx.level = RAW_LOCK_LOCKX;
252         io.lockx.in.file.fnum = fnum;
253         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
254         io.lockx.in.timeout = 0;
255         io.lockx.in.ulock_cnt = 0;
256         io.lockx.in.lock_cnt = 1;
257         lock[0].pid = cli->session->pid;
258         lock[0].offset = 10;
259         lock[0].count = 1;
260         io.lockx.in.locks = &lock[0];
261         status = smb_raw_lock(cli->tree, &io);
262         CHECK_STATUS(status, NT_STATUS_OK);
263
264
265         torture_comment(tctx, "Trying 0xEEFFFFFF 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 = 0xEEFFFFFF;
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_LOCK_NOT_GRANTED);
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 0xEF000000 lock\n");
284         io.lockx.in.ulock_cnt = 0;
285         io.lockx.in.lock_cnt = 1;
286         lock[0].count = 4000;
287         lock[0].offset = 0xEF000000;
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_FILE_LOCK_CONFLICT);
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 zero 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 max lock\n");
320         io.lockx.in.ulock_cnt = 0;
321         io.lockx.in.lock_cnt = 1;
322         lock[0].count = 0;
323         lock[0].offset = ~0;
324         status = smb_raw_lock(cli->tree, &io);
325         CHECK_STATUS(status, NT_STATUS_OK);
326         lock[0].pid++;
327         status = smb_raw_lock(cli->tree, &io);
328         CHECK_STATUS(status, NT_STATUS_OK);
329         lock[0].pid--;
330         io.lockx.in.ulock_cnt = 1;
331         io.lockx.in.lock_cnt = 0;
332         status = smb_raw_lock(cli->tree, &io);
333         CHECK_STATUS(status, NT_STATUS_OK);
334         status = smb_raw_lock(cli->tree, &io);
335         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
336
337         torture_comment(tctx, "Trying 2^63\n");
338         io.lockx.in.ulock_cnt = 0;
339         io.lockx.in.lock_cnt = 1;
340         lock[0].count = 1;
341         lock[0].offset = 1;
342         lock[0].offset <<= 63;
343         status = smb_raw_lock(cli->tree, &io);
344         CHECK_STATUS(status, NT_STATUS_OK);
345         lock[0].pid++;
346         status = smb_raw_lock(cli->tree, &io);
347         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
348         lock[0].pid--;
349         io.lockx.in.ulock_cnt = 1;
350         io.lockx.in.lock_cnt = 0;
351         status = smb_raw_lock(cli->tree, &io);
352         CHECK_STATUS(status, NT_STATUS_OK);
353         status = smb_raw_lock(cli->tree, &io);
354         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
355
356         torture_comment(tctx, "Trying 2^63 - 1\n");
357         io.lockx.in.ulock_cnt = 0;
358         io.lockx.in.lock_cnt = 1;
359         lock[0].count = 1;
360         lock[0].offset = 1;
361         lock[0].offset <<= 63;
362         lock[0].offset--;
363         status = smb_raw_lock(cli->tree, &io);
364         CHECK_STATUS(status, NT_STATUS_OK);
365         lock[0].pid++;
366         status = smb_raw_lock(cli->tree, &io);
367         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
368         lock[0].pid--;
369         io.lockx.in.ulock_cnt = 1;
370         io.lockx.in.lock_cnt = 0;
371         status = smb_raw_lock(cli->tree, &io);
372         CHECK_STATUS(status, NT_STATUS_OK);
373         status = smb_raw_lock(cli->tree, &io);
374         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
375
376         torture_comment(tctx, "Trying max lock 2\n");
377         io.lockx.in.ulock_cnt = 0;
378         io.lockx.in.lock_cnt = 1;
379         lock[0].count = 1;
380         lock[0].offset = ~0;
381         status = smb_raw_lock(cli->tree, &io);
382         CHECK_STATUS(status, NT_STATUS_OK);
383         lock[0].pid++;
384         lock[0].count = 2;
385         status = smb_raw_lock(cli->tree, &io);
386         if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(tctx))
387                 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
388         else
389                 CHECK_STATUS(status, NT_STATUS_OK);
390         lock[0].pid--;
391         io.lockx.in.ulock_cnt = 1;
392         io.lockx.in.lock_cnt = 0;
393         lock[0].count = 1;
394         status = smb_raw_lock(cli->tree, &io);
395
396         CHECK_STATUS(status, NT_STATUS_OK);
397         status = smb_raw_lock(cli->tree, &io);
398         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
399
400 done:
401         smbcli_close(cli->tree, fnum);
402         smb_raw_exit(cli->session);
403         smbcli_deltree(cli->tree, BASEDIR);
404         return ret;
405 }
406
407 /*
408   test high pid
409 */
410 static bool test_pidhigh(struct torture_context *tctx, 
411                                                  struct smbcli_state *cli)
412 {
413         union smb_lock io;
414         struct smb_lock_entry lock[1];
415         NTSTATUS status;
416         bool ret = true;
417         int fnum;
418         const char *fname = BASEDIR "\\test.txt";
419         uint8_t c = 1;
420
421         if (!torture_setup_dir(cli, BASEDIR)) {
422                 return false;
423         }
424
425         torture_comment(tctx, "Testing high pid\n");
426         io.generic.level = RAW_LOCK_LOCKX;
427
428         cli->session->pid = 1;
429         
430         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
431         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
432                        "Failed to create %s - %s\n",
433                        fname, smbcli_errstr(cli->tree)));
434
435         if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
436                 torture_result(tctx, TORTURE_FAIL,
437                         "Failed to write 1 byte - %s\n",
438                         smbcli_errstr(cli->tree));
439                 ret = false;
440                 goto done;
441         }
442
443         io.lockx.level = RAW_LOCK_LOCKX;
444         io.lockx.in.file.fnum = fnum;
445         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
446         io.lockx.in.timeout = 0;
447         io.lockx.in.ulock_cnt = 0;
448         io.lockx.in.lock_cnt = 1;
449         lock[0].pid = cli->session->pid;
450         lock[0].offset = 0;
451         lock[0].count = 0xFFFFFFFF;
452         io.lockx.in.locks = &lock[0];
453         status = smb_raw_lock(cli->tree, &io);
454         CHECK_STATUS(status, NT_STATUS_OK);
455
456         if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
457                 torture_result(tctx, TORTURE_FAIL,
458                         "Failed to read 1 byte - %s\n",
459                         smbcli_errstr(cli->tree));
460                 ret = false;
461                 goto done;
462         }
463
464         cli->session->pid = 2;
465
466         if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
467                 torture_result(tctx, TORTURE_FAIL,
468                         "pid is incorrect handled for read with lock!\n");
469                 ret = false;
470                 goto done;
471         }
472
473         cli->session->pid = 0x10001;
474
475         if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
476                 torture_result(tctx, TORTURE_FAIL,
477                         "High pid is used on this server!\n");
478                 ret = false;
479         } else {
480                 torture_warning(tctx, "High pid is not used on this server (correct)\n");
481         }
482
483 done:
484         smbcli_close(cli->tree, fnum);
485         smb_raw_exit(cli->session);
486         smbcli_deltree(cli->tree, BASEDIR);
487         return ret;
488 }
489
490
491 /*
492   test locking&X async operation
493 */
494 static bool test_async(struct torture_context *tctx, 
495                                            struct smbcli_state *cli)
496 {
497         struct smbcli_session *session;
498         struct smb_composite_sesssetup setup;
499         struct smbcli_tree *tree;
500         union smb_tcon tcon;
501         const char *host, *share;
502         union smb_lock io;
503         struct smb_lock_entry lock[2];
504         NTSTATUS status;
505         bool ret = true;
506         int fnum;
507         const char *fname = BASEDIR "\\test.txt";
508         time_t t;
509         struct smbcli_request *req, *req2;
510         struct smbcli_session_options options;
511
512         if (!torture_setup_dir(cli, BASEDIR)) {
513                 return false;
514         }
515
516         lp_smbcli_session_options(tctx->lp_ctx, &options);
517
518         torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
519         io.generic.level = RAW_LOCK_LOCKX;
520
521         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
522         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
523                        "Failed to create %s - %s\n",
524                        fname, smbcli_errstr(cli->tree)));
525
526         io.lockx.level = RAW_LOCK_LOCKX;
527         io.lockx.in.file.fnum = fnum;
528         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
529         io.lockx.in.timeout = 0;
530         io.lockx.in.ulock_cnt = 0;
531         io.lockx.in.lock_cnt = 1;
532         lock[0].pid = cli->session->pid;
533         lock[0].offset = 100;
534         lock[0].count = 10;
535         lock[1].pid = cli->session->pid;
536         lock[1].offset = 110;
537         lock[1].count = 10;
538         io.lockx.in.locks = &lock[0];
539         status = smb_raw_lock(cli->tree, &io);
540         CHECK_STATUS(status, NT_STATUS_OK);
541
542         t = time(NULL);
543
544         torture_comment(tctx, "testing cancel by CANCEL_LOCK\n");
545
546         /* setup a timed lock */
547         io.lockx.in.timeout = 10000;
548         req = smb_raw_lock_send(cli->tree, &io);
549         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
550                        "Failed to setup timed lock (%s)\n", __location__));
551
552         /* cancel the wrong range */
553         lock[0].offset = 0;
554         io.lockx.in.timeout = 0;
555         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
556         status = smb_raw_lock(cli->tree, &io);
557         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
558
559         /* cancel with the wrong bits set */
560         lock[0].offset = 100;
561         io.lockx.in.timeout = 0;
562         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
563         status = smb_raw_lock(cli->tree, &io);
564         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
565
566         /* cancel the right range */
567         lock[0].offset = 100;
568         io.lockx.in.timeout = 0;
569         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
570         status = smb_raw_lock(cli->tree, &io);
571         CHECK_STATUS(status, NT_STATUS_OK);
572
573         /* receive the failed lock request */
574         status = smbcli_request_simple_recv(req);
575         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
576
577         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
578                        "lock cancel was not immediate (%s)\n", __location__));
579
580         /* MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
581          * if the lock vector contains one entry. When given mutliple cancel
582          * requests in a single PDU we expect the server to return an
583          * error. Samba4 handles this correctly. Windows servers seem to
584          * accept the request but only cancel the first lock.  Samba3
585          * now does what Windows does (JRA).
586          */
587         torture_comment(tctx, "testing multiple cancel\n");
588
589         /* acquire second lock */
590         io.lockx.in.timeout = 0;
591         io.lockx.in.ulock_cnt = 0;
592         io.lockx.in.lock_cnt = 1;
593         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
594         io.lockx.in.locks = &lock[1];
595         status = smb_raw_lock(cli->tree, &io);
596         CHECK_STATUS(status, NT_STATUS_OK);
597
598         /* setup 2 timed locks */
599         t = time(NULL);
600         io.lockx.in.timeout = 10000;
601         io.lockx.in.lock_cnt = 1;
602         io.lockx.in.locks = &lock[0];
603         req = smb_raw_lock_send(cli->tree, &io);
604         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
605                        "Failed to setup timed lock (%s)\n", __location__));
606         io.lockx.in.locks = &lock[1];
607         req2 = smb_raw_lock_send(cli->tree, &io);
608         torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
609                        "Failed to setup timed lock (%s)\n", __location__));
610
611         /* try to cancel both locks in the same packet */
612         io.lockx.in.timeout = 0;
613         io.lockx.in.lock_cnt = 2;
614         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
615         io.lockx.in.locks = lock;
616         status = smb_raw_lock(cli->tree, &io);
617         CHECK_STATUS(status, NT_STATUS_OK);
618
619         torture_warning(tctx, "Target server accepted a lock cancel "
620                               "request with multiple locks. This violates "
621                               "MS-CIFS 2.2.4.32.1.\n");
622
623         /* receive the failed lock requests */
624         status = smbcli_request_simple_recv(req);
625         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
626
627         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
628                        "first lock was not cancelled immediately (%s)\n",
629                        __location__));
630
631         /* send cancel to second lock */
632         io.lockx.in.timeout = 0;
633         io.lockx.in.lock_cnt = 1;
634         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK |
635                            LOCKING_ANDX_LARGE_FILES;
636         io.lockx.in.locks = &lock[1];
637         status = smb_raw_lock(cli->tree, &io);
638         CHECK_STATUS(status, NT_STATUS_OK);
639
640         status = smbcli_request_simple_recv(req2);
641         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
642
643         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
644                        "second lock was not cancelled immediately (%s)\n",
645                        __location__));
646
647         /* cleanup the second lock */
648         io.lockx.in.ulock_cnt = 1;
649         io.lockx.in.lock_cnt = 0;
650         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
651         io.lockx.in.locks = &lock[1];
652         status = smb_raw_lock(cli->tree, &io);
653         CHECK_STATUS(status, NT_STATUS_OK);
654
655         /* If a lock request contained multiple ranges and we are cancelling
656          * one while it's still pending, what happens? */
657         torture_comment(tctx, "testing cancel 1/2 lock request\n");
658
659         /* Send request with two ranges */
660         io.lockx.in.timeout = -1;
661         io.lockx.in.ulock_cnt = 0;
662         io.lockx.in.lock_cnt = 2;
663         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
664         io.lockx.in.locks = lock;
665         req = smb_raw_lock_send(cli->tree, &io);
666         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
667                        "Failed to setup pending lock (%s)\n", __location__));
668
669         /* Try to cancel the first lock range */
670         io.lockx.in.timeout = 0;
671         io.lockx.in.lock_cnt = 1;
672         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
673         io.lockx.in.locks = &lock[0];
674         status = smb_raw_lock(cli->tree, &io);
675         CHECK_STATUS(status, NT_STATUS_OK);
676
677         /* Locking request should've failed and second range should be
678          * unlocked */
679         status = smbcli_request_simple_recv(req);
680         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
681
682         io.lockx.in.timeout = 0;
683         io.lockx.in.ulock_cnt = 0;
684         io.lockx.in.lock_cnt = 1;
685         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
686         io.lockx.in.locks = &lock[1];
687         status = smb_raw_lock(cli->tree, &io);
688         CHECK_STATUS(status, NT_STATUS_OK);
689
690         /* Cleanup both locks */
691         io.lockx.in.ulock_cnt = 2;
692         io.lockx.in.lock_cnt = 0;
693         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
694         io.lockx.in.locks = lock;
695         status = smb_raw_lock(cli->tree, &io);
696         CHECK_STATUS(status, NT_STATUS_OK);
697
698         torture_comment(tctx, "testing cancel 2/2 lock request\n");
699
700         /* Lock second range so it contends */
701         io.lockx.in.timeout = 0;
702         io.lockx.in.ulock_cnt = 0;
703         io.lockx.in.lock_cnt = 1;
704         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
705         io.lockx.in.locks = &lock[1];
706         status = smb_raw_lock(cli->tree, &io);
707         CHECK_STATUS(status, NT_STATUS_OK);
708
709         /* Send request with two ranges */
710         io.lockx.in.timeout = -1;
711         io.lockx.in.ulock_cnt = 0;
712         io.lockx.in.lock_cnt = 2;
713         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
714         io.lockx.in.locks = lock;
715         req = smb_raw_lock_send(cli->tree, &io);
716         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
717                        "Failed to setup pending lock (%s)\n", __location__));
718
719         /* Try to cancel the second lock range */
720         io.lockx.in.timeout = 0;
721         io.lockx.in.lock_cnt = 1;
722         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
723         io.lockx.in.locks = &lock[1];
724         status = smb_raw_lock(cli->tree, &io);
725         CHECK_STATUS(status, NT_STATUS_OK);
726
727         /* Locking request should've failed and first range should be
728          * unlocked */
729         status = smbcli_request_simple_recv(req);
730         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
731
732         io.lockx.in.timeout = 0;
733         io.lockx.in.ulock_cnt = 0;
734         io.lockx.in.lock_cnt = 1;
735         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
736         io.lockx.in.locks = &lock[0];
737         status = smb_raw_lock(cli->tree, &io);
738         CHECK_STATUS(status, NT_STATUS_OK);
739
740         /* Cleanup both locks */
741         io.lockx.in.ulock_cnt = 2;
742         io.lockx.in.lock_cnt = 0;
743         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
744         io.lockx.in.locks = lock;
745         status = smb_raw_lock(cli->tree, &io);
746         CHECK_STATUS(status, NT_STATUS_OK);
747
748         torture_comment(tctx, "testing cancel by unlock\n");
749         io.lockx.in.ulock_cnt = 0;
750         io.lockx.in.lock_cnt = 1;
751         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
752         io.lockx.in.timeout = 0;
753         io.lockx.in.locks = &lock[0];
754         status = smb_raw_lock(cli->tree, &io);
755         CHECK_STATUS(status, NT_STATUS_OK);
756
757         io.lockx.in.timeout = 5000;
758         req = smb_raw_lock_send(cli->tree, &io);
759         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
760                        "Failed to setup timed lock (%s)\n", __location__));
761
762         io.lockx.in.ulock_cnt = 1;
763         io.lockx.in.lock_cnt = 0;
764         status = smb_raw_lock(cli->tree, &io);
765         CHECK_STATUS(status, NT_STATUS_OK);
766
767         t = time(NULL);
768         status = smbcli_request_simple_recv(req);
769         CHECK_STATUS(status, NT_STATUS_OK);
770
771         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
772                        "lock cancel by unlock was not immediate (%s) - took %d secs\n",
773                        __location__, (int)(time(NULL)-t)));
774
775         torture_comment(tctx, "testing cancel by close\n");
776         io.lockx.in.ulock_cnt = 0;
777         io.lockx.in.lock_cnt = 1;
778         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
779         io.lockx.in.timeout = 0;
780         status = smb_raw_lock(cli->tree, &io);
781         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
782
783         t = time(NULL);
784         io.lockx.in.timeout = 10000;
785         req = smb_raw_lock_send(cli->tree, &io);
786         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
787                        "Failed to setup timed lock (%s)\n", __location__));
788
789         status = smbcli_close(cli->tree, fnum);
790         CHECK_STATUS(status, NT_STATUS_OK);
791
792         status = smbcli_request_simple_recv(req);
793         if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
794                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
795         else
796                 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
797
798         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
799                        "lock cancel by close was not immediate (%s)\n", __location__));
800
801         torture_comment(tctx, "create a new sessions\n");
802         session = smbcli_session_init(cli->transport, tctx, false, options);
803         setup.in.sesskey = cli->transport->negotiate.sesskey;
804         setup.in.capabilities = cli->transport->negotiate.capabilities;
805         setup.in.workgroup = lp_workgroup(tctx->lp_ctx);
806         setup.in.credentials = cmdline_credentials;
807         setup.in.gensec_settings = lp_gensec_settings(tctx, tctx->lp_ctx);
808         status = smb_composite_sesssetup(session, &setup);
809         CHECK_STATUS(status, NT_STATUS_OK);
810         session->vuid = setup.out.vuid;
811
812         torture_comment(tctx, "create new tree context\n");
813         share = torture_setting_string(tctx, "share", NULL);
814         host  = torture_setting_string(tctx, "host", NULL);
815         tree = smbcli_tree_init(session, tctx, false);
816         tcon.generic.level = RAW_TCON_TCONX;
817         tcon.tconx.in.flags = 0;
818         tcon.tconx.in.password = data_blob(NULL, 0);
819         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
820         tcon.tconx.in.device = "A:";
821         status = smb_raw_tcon(tree, tctx, &tcon);
822         CHECK_STATUS(status, NT_STATUS_OK);
823         tree->tid = tcon.tconx.out.tid;
824
825         torture_comment(tctx, "testing cancel by exit\n");
826         if (TARGET_SUPPORTS_SMBEXIT(tctx)) {
827                 fname = BASEDIR "\\test_exit.txt";
828                 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
829                 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
830                                "Failed to reopen %s - %s\n",
831                                fname, smbcli_errstr(tree)));
832
833                 io.lockx.level = RAW_LOCK_LOCKX;
834                 io.lockx.in.file.fnum = fnum;
835                 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
836                 io.lockx.in.timeout = 0;
837                 io.lockx.in.ulock_cnt = 0;
838                 io.lockx.in.lock_cnt = 1;
839                 lock[0].pid = session->pid;
840                 lock[0].offset = 100;
841                 lock[0].count = 10;
842                 io.lockx.in.locks = &lock[0];
843                 status = smb_raw_lock(tree, &io);
844                 CHECK_STATUS(status, NT_STATUS_OK);
845
846                 io.lockx.in.ulock_cnt = 0;
847                 io.lockx.in.lock_cnt = 1;
848                 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
849                 io.lockx.in.timeout = 0;
850                 status = smb_raw_lock(tree, &io);
851                 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
852
853                 io.lockx.in.timeout = 10000;
854                 t = time(NULL);
855                 req = smb_raw_lock_send(tree, &io);
856                 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
857                                "Failed to setup timed lock (%s)\n",
858                                __location__));
859
860                 status = smb_raw_exit(session);
861                 CHECK_STATUS(status, NT_STATUS_OK);
862
863                 status = smbcli_request_simple_recv(req);
864                 if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
865                         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
866                 else
867                         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
868
869                 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
870                                "lock cancel by exit was not immediate (%s)\n",
871                                __location__));
872         }
873         else {
874                 torture_comment(tctx,
875                                 "  skipping test, SMBExit not supported\n");
876         }
877
878         torture_comment(tctx, "testing cancel by ulogoff\n");
879         fname = BASEDIR "\\test_ulogoff.txt";
880         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
881         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
882                        "Failed to reopen %s - %s\n",
883                        fname, smbcli_errstr(tree)));
884
885         io.lockx.level = RAW_LOCK_LOCKX;
886         io.lockx.in.file.fnum = fnum;
887         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
888         io.lockx.in.timeout = 0;
889         io.lockx.in.ulock_cnt = 0;
890         io.lockx.in.lock_cnt = 1;
891         lock[0].pid = session->pid;
892         lock[0].offset = 100;
893         lock[0].count = 10;
894         io.lockx.in.locks = &lock[0];
895         status = smb_raw_lock(tree, &io);
896         CHECK_STATUS(status, NT_STATUS_OK);
897
898         io.lockx.in.ulock_cnt = 0;
899         io.lockx.in.lock_cnt = 1;
900         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
901         io.lockx.in.timeout = 0;
902         status = smb_raw_lock(tree, &io);
903         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
904
905         io.lockx.in.timeout = 10000;
906         t = time(NULL);
907         req = smb_raw_lock_send(tree, &io);
908         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
909                        "Failed to setup timed lock (%s)\n", __location__));
910
911         status = smb_raw_ulogoff(session);
912         CHECK_STATUS(status, NT_STATUS_OK);
913
914         status = smbcli_request_simple_recv(req);
915         if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx)) {
916                 if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
917                         torture_result(tctx, TORTURE_FAIL,
918                                 "lock not canceled by ulogoff - %s "
919                                 "(ignored because of vfs_vifs fails it)\n",
920                                 nt_errstr(status));
921                         smb_tree_disconnect(tree);
922                         smb_raw_exit(session);
923                         goto done;
924                 }
925                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
926         } else {
927                 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
928         }
929
930         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
931                        "lock cancel by ulogoff was not immediate (%s)\n", __location__));
932
933         torture_comment(tctx, "testing cancel by tdis\n");
934         tree->session = cli->session;
935
936         fname = BASEDIR "\\test_tdis.txt";
937         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
938         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
939                        "Failed to reopen %s - %s\n",
940                        fname, smbcli_errstr(tree)));
941
942         io.lockx.level = RAW_LOCK_LOCKX;
943         io.lockx.in.file.fnum = fnum;
944         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
945         io.lockx.in.timeout = 0;
946         io.lockx.in.ulock_cnt = 0;
947         io.lockx.in.lock_cnt = 1;
948         lock[0].pid = cli->session->pid;
949         lock[0].offset = 100;
950         lock[0].count = 10;
951         io.lockx.in.locks = &lock[0];
952         status = smb_raw_lock(tree, &io);
953         CHECK_STATUS(status, NT_STATUS_OK);
954
955         status = smb_raw_lock(tree, &io);
956         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
957
958         io.lockx.in.timeout = 10000;
959         t = time(NULL);
960         req = smb_raw_lock_send(tree, &io);
961         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
962                        "Failed to setup timed lock (%s)\n", __location__));
963
964         status = smb_tree_disconnect(tree);
965         CHECK_STATUS(status, NT_STATUS_OK);
966
967         status = smbcli_request_simple_recv(req);
968         if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
969                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
970         else
971                 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
972
973         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
974                        "lock cancel by tdis was not immediate (%s)\n", __location__));
975
976 done:
977         smb_raw_exit(cli->session);
978         smbcli_deltree(cli->tree, BASEDIR);
979         return ret;
980 }
981
982 /*
983   test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
984 */
985 static bool test_errorcode(struct torture_context *tctx, 
986                                                    struct smbcli_state *cli)
987 {
988         union smb_lock io;
989         union smb_open op;
990         struct smb_lock_entry lock[2];
991         NTSTATUS status;
992         bool ret = true;
993         int fnum, fnum2;
994         const char *fname;
995         struct smbcli_request *req;
996         time_t start;
997         int t;
998         int delay;
999         uint16_t deny_mode = 0;
1000
1001         if (!torture_setup_dir(cli, BASEDIR)) {
1002                 return false;
1003         }
1004
1005         torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
1006
1007         torture_comment(tctx, "testing with timeout = 0\n");
1008         fname = BASEDIR "\\test0.txt";
1009         t = 0;
1010
1011         /*
1012          * the first run is with t = 0,
1013          * the second with t > 0 (=1)
1014          */
1015 next_run:
1016         /*
1017          * use the DENY_DOS mode, that creates two fnum's of one low-level
1018          * file handle, this demonstrates that the cache is per fnum, not
1019          * per file handle
1020          */
1021         if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
1022             deny_mode = OPENX_MODE_DENY_DOS;
1023         else
1024             deny_mode = OPENX_MODE_DENY_NONE;
1025
1026         op.openx.level = RAW_OPEN_OPENX;
1027         op.openx.in.fname = fname;
1028         op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1029         op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
1030         op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
1031         op.openx.in.search_attrs = 0;
1032         op.openx.in.file_attrs = 0;
1033         op.openx.in.write_time = 0;
1034         op.openx.in.size = 0;
1035         op.openx.in.timeout = 0;
1036
1037         status = smb_raw_open(cli->tree, tctx, &op);
1038         CHECK_STATUS(status, NT_STATUS_OK);
1039         fnum = op.openx.out.file.fnum;
1040
1041         status = smb_raw_open(cli->tree, tctx, &op);
1042         CHECK_STATUS(status, NT_STATUS_OK);
1043         fnum2 = op.openx.out.file.fnum;
1044
1045         io.lockx.level = RAW_LOCK_LOCKX;
1046         io.lockx.in.file.fnum = fnum;
1047         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1048         io.lockx.in.timeout = t;
1049         io.lockx.in.ulock_cnt = 0;
1050         io.lockx.in.lock_cnt = 1;
1051         lock[0].pid = cli->session->pid;
1052         lock[0].offset = 100;
1053         lock[0].count = 10;
1054         io.lockx.in.locks = &lock[0];
1055         status = smb_raw_lock(cli->tree, &io);
1056         CHECK_STATUS(status, NT_STATUS_OK);
1057
1058         /*
1059          * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
1060          * this also demonstrates that the error code cache is per file handle
1061          * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
1062          */
1063         io.lockx.in.file.fnum = fnum2;
1064         status = smb_raw_lock(cli->tree, &io);
1065         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1066
1067         io.lockx.in.file.fnum = fnum;
1068         status = smb_raw_lock(cli->tree, &io);
1069         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1070
1071         /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
1072         io.lockx.in.file.fnum = fnum;
1073         status = smb_raw_lock(cli->tree, &io);
1074         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1075
1076         io.lockx.in.file.fnum = fnum2;
1077         status = smb_raw_lock(cli->tree, &io);
1078         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1079
1080         io.lockx.in.file.fnum = fnum;
1081         status = smb_raw_lock(cli->tree, &io);
1082         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1083
1084         io.lockx.in.file.fnum = fnum2;
1085         status = smb_raw_lock(cli->tree, &io);
1086         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1087
1088         /* demonstrate that the smbpid doesn't matter */
1089         lock[0].pid++;
1090         io.lockx.in.file.fnum = fnum;
1091         status = smb_raw_lock(cli->tree, &io);
1092         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1093
1094         io.lockx.in.file.fnum = fnum2;
1095         status = smb_raw_lock(cli->tree, &io);
1096         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1097         lock[0].pid--;
1098
1099         /* 
1100          * demonstrate the a successful lock with count = 0 and the same offset,
1101          * doesn't reset the error cache
1102          */
1103         lock[0].offset = 100;
1104         lock[0].count = 0;
1105         io.lockx.in.file.fnum = fnum;
1106         status = smb_raw_lock(cli->tree, &io);
1107         CHECK_STATUS(status, NT_STATUS_OK);
1108
1109         io.lockx.in.file.fnum = fnum2;
1110         status = smb_raw_lock(cli->tree, &io);
1111         CHECK_STATUS(status, NT_STATUS_OK);
1112
1113         lock[0].offset = 100;
1114         lock[0].count = 10;
1115         io.lockx.in.file.fnum = fnum;
1116         status = smb_raw_lock(cli->tree, &io);
1117         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1118
1119         io.lockx.in.file.fnum = fnum2;
1120         status = smb_raw_lock(cli->tree, &io);
1121         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1122
1123         /* 
1124          * demonstrate the a successful lock with count = 0 and outside the locked range,
1125          * doesn't reset the error cache
1126          */
1127         lock[0].offset = 110;
1128         lock[0].count = 0;
1129         io.lockx.in.file.fnum = fnum;
1130         status = smb_raw_lock(cli->tree, &io);
1131         CHECK_STATUS(status, NT_STATUS_OK);
1132
1133         io.lockx.in.file.fnum = fnum2;
1134         status = smb_raw_lock(cli->tree, &io);
1135         CHECK_STATUS(status, NT_STATUS_OK);
1136
1137         lock[0].offset = 100;
1138         lock[0].count = 10;
1139         io.lockx.in.file.fnum = fnum;
1140         status = smb_raw_lock(cli->tree, &io);
1141         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1142
1143         io.lockx.in.file.fnum = fnum2;
1144         status = smb_raw_lock(cli->tree, &io);
1145         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1146
1147         lock[0].offset = 99;
1148         lock[0].count = 0;
1149         io.lockx.in.file.fnum = fnum;
1150         status = smb_raw_lock(cli->tree, &io);
1151         CHECK_STATUS(status, NT_STATUS_OK);
1152
1153         io.lockx.in.file.fnum = fnum2;
1154         status = smb_raw_lock(cli->tree, &io);
1155         CHECK_STATUS(status, NT_STATUS_OK);
1156
1157         lock[0].offset = 100;
1158         lock[0].count = 10;
1159         io.lockx.in.file.fnum = fnum;
1160         status = smb_raw_lock(cli->tree, &io);
1161         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1162
1163         io.lockx.in.file.fnum = fnum2;
1164         status = smb_raw_lock(cli->tree, &io);
1165         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1166
1167         /* demonstrate that a changing count doesn't reset the error cache */
1168         lock[0].offset = 100;
1169         lock[0].count = 5;
1170         io.lockx.in.file.fnum = fnum;
1171         status = smb_raw_lock(cli->tree, &io);
1172         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1173
1174         io.lockx.in.file.fnum = fnum2;
1175         status = smb_raw_lock(cli->tree, &io);
1176         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1177
1178         lock[0].offset = 100;
1179         lock[0].count = 15;
1180         io.lockx.in.file.fnum = fnum;
1181         status = smb_raw_lock(cli->tree, &io);
1182         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1183
1184         io.lockx.in.file.fnum = fnum2;
1185         status = smb_raw_lock(cli->tree, &io);
1186         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1187
1188         /* 
1189          * demonstrate the a lock with count = 0 and inside the locked range,
1190          * fails and resets the error cache
1191          */
1192         lock[0].offset = 101;
1193         lock[0].count = 0;
1194         io.lockx.in.file.fnum = fnum;
1195         status = smb_raw_lock(cli->tree, &io);
1196         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1197         status = smb_raw_lock(cli->tree, &io);
1198         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1199
1200         io.lockx.in.file.fnum = fnum2;
1201         status = smb_raw_lock(cli->tree, &io);
1202         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1203         status = smb_raw_lock(cli->tree, &io);
1204         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1205
1206         lock[0].offset = 100;
1207         lock[0].count = 10;
1208         io.lockx.in.file.fnum = fnum;
1209         status = smb_raw_lock(cli->tree, &io);
1210         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1211         status = smb_raw_lock(cli->tree, &io);
1212         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1213
1214         io.lockx.in.file.fnum = fnum2;
1215         status = smb_raw_lock(cli->tree, &io);
1216         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1217         status = smb_raw_lock(cli->tree, &io);
1218         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1219
1220         /* demonstrate the a changing offset, resets the error cache */
1221         lock[0].offset = 105;
1222         lock[0].count = 10;
1223         io.lockx.in.file.fnum = fnum;
1224         status = smb_raw_lock(cli->tree, &io);
1225         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1226         status = smb_raw_lock(cli->tree, &io);
1227         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1228
1229         io.lockx.in.file.fnum = fnum2;
1230         status = smb_raw_lock(cli->tree, &io);
1231         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1232         status = smb_raw_lock(cli->tree, &io);
1233         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1234
1235         lock[0].offset = 100;
1236         lock[0].count = 10;
1237         io.lockx.in.file.fnum = fnum;
1238         status = smb_raw_lock(cli->tree, &io);
1239         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1240         status = smb_raw_lock(cli->tree, &io);
1241         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1242
1243         io.lockx.in.file.fnum = fnum2;
1244         status = smb_raw_lock(cli->tree, &io);
1245         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1246         status = smb_raw_lock(cli->tree, &io);
1247         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1248
1249         lock[0].offset = 95;
1250         lock[0].count = 9;
1251         io.lockx.in.file.fnum = fnum;
1252         status = smb_raw_lock(cli->tree, &io);
1253         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1254         status = smb_raw_lock(cli->tree, &io);
1255         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1256
1257         io.lockx.in.file.fnum = fnum2;
1258         status = smb_raw_lock(cli->tree, &io);
1259         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1260         status = smb_raw_lock(cli->tree, &io);
1261         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1262
1263         lock[0].offset = 100;
1264         lock[0].count = 10;
1265         io.lockx.in.file.fnum = fnum;
1266         status = smb_raw_lock(cli->tree, &io);
1267         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1268         status = smb_raw_lock(cli->tree, &io);
1269         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1270
1271         io.lockx.in.file.fnum = fnum2;
1272         status = smb_raw_lock(cli->tree, &io);
1273         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1274         status = smb_raw_lock(cli->tree, &io);
1275         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1276
1277         /* 
1278          * demonstrate the a successful lock in a different range, 
1279          * doesn't reset the cache, the failing lock on the 2nd handle
1280          * resets the cache
1281          */
1282         lock[0].offset = 120;
1283         lock[0].count = 15;
1284         io.lockx.in.file.fnum = fnum;
1285         status = smb_raw_lock(cli->tree, &io);
1286         CHECK_STATUS(status, NT_STATUS_OK);
1287
1288         io.lockx.in.file.fnum = fnum2;
1289         status = smb_raw_lock(cli->tree, &io);
1290         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1291
1292         lock[0].offset = 100;
1293         lock[0].count = 10;
1294         io.lockx.in.file.fnum = fnum;
1295         status = smb_raw_lock(cli->tree, &io);
1296         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1297         status = smb_raw_lock(cli->tree, &io);
1298         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1299
1300         io.lockx.in.file.fnum = fnum2;
1301         status = smb_raw_lock(cli->tree, &io);
1302         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1303         status = smb_raw_lock(cli->tree, &io);
1304         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1305
1306         /* end of the loop */
1307         if (t == 0) {
1308                 smb_raw_exit(cli->session);
1309                 t = 1;
1310                 torture_comment(tctx, "testing with timeout > 0 (=%d)\n",
1311                                 t);
1312                 fname = BASEDIR "\\test1.txt";
1313                 goto next_run;
1314         }
1315
1316         t = 4000;
1317         torture_comment(tctx, "testing special cases with timeout > 0 (=%d)\n",
1318                         t);
1319
1320         /*
1321          * the following 3 test sections demonstrate that
1322          * the cache is only set when the error is reported
1323          * to the client (after the timeout went by)
1324          */
1325         smb_raw_exit(cli->session);
1326         torture_comment(tctx, "testing a conflict while a lock is pending\n");
1327         fname = BASEDIR "\\test2.txt";
1328         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1329         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1330                        "Failed to reopen %s - %s\n",
1331                        fname, smbcli_errstr(cli->tree)));
1332
1333         io.lockx.level = RAW_LOCK_LOCKX;
1334         io.lockx.in.file.fnum = fnum;
1335         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1336         io.lockx.in.timeout = 0;
1337         io.lockx.in.ulock_cnt = 0;
1338         io.lockx.in.lock_cnt = 1;
1339         lock[0].pid = cli->session->pid;
1340         lock[0].offset = 100;
1341         lock[0].count = 10;
1342         io.lockx.in.locks = &lock[0];
1343         status = smb_raw_lock(cli->tree, &io);
1344         CHECK_STATUS(status, NT_STATUS_OK);
1345
1346         start = time(NULL);
1347         io.lockx.in.timeout = t;
1348         req = smb_raw_lock_send(cli->tree, &io);
1349         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1350                        "Failed to setup timed lock (%s)\n", __location__));
1351
1352         io.lockx.in.timeout = 0;
1353         lock[0].offset = 105;
1354         lock[0].count = 10;
1355         status = smb_raw_lock(cli->tree, &io);
1356         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1357
1358         status = smbcli_request_simple_recv(req);
1359         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1360
1361         delay = t / 1000;
1362         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1363                 delay /= 2;
1364         }
1365
1366         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1367                        "lock comes back to early timeout[%d] delay[%d]"
1368                        "(%s)\n", t, delay, __location__));
1369
1370         status = smb_raw_lock(cli->tree, &io);
1371         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1372
1373         smbcli_close(cli->tree, fnum);
1374         fname = BASEDIR "\\test3.txt";
1375         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1376         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1377                        "Failed to reopen %s - %s\n",
1378                        fname, smbcli_errstr(cli->tree)));
1379
1380         io.lockx.level = RAW_LOCK_LOCKX;
1381         io.lockx.in.file.fnum = fnum;
1382         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1383         io.lockx.in.timeout = 0;
1384         io.lockx.in.ulock_cnt = 0;
1385         io.lockx.in.lock_cnt = 1;
1386         lock[0].pid = cli->session->pid;
1387         lock[0].offset = 100;
1388         lock[0].count = 10;
1389         io.lockx.in.locks = &lock[0];
1390         status = smb_raw_lock(cli->tree, &io);
1391         CHECK_STATUS(status, NT_STATUS_OK);
1392
1393         start = time(NULL);
1394         io.lockx.in.timeout = t;
1395         req = smb_raw_lock_send(cli->tree, &io);
1396         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1397                        "Failed to setup timed lock (%s)\n", __location__));
1398
1399         io.lockx.in.timeout = 0;
1400         lock[0].offset = 105;
1401         lock[0].count = 10;
1402         status = smb_raw_lock(cli->tree, &io);
1403         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1404
1405         status = smbcli_request_simple_recv(req);
1406         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1407
1408         delay = t / 1000;
1409         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1410                 delay /= 2;
1411         }
1412
1413         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1414                        "lock comes back to early timeout[%d] delay[%d]"
1415                        "(%s)\n", t, delay, __location__));
1416
1417         lock[0].offset = 100;
1418         lock[0].count = 10;
1419         status = smb_raw_lock(cli->tree, &io);
1420         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1421
1422         smbcli_close(cli->tree, fnum);
1423         fname = BASEDIR "\\test4.txt";
1424         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1425         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1426                        "Failed to reopen %s - %s\n",
1427                        fname, smbcli_errstr(cli->tree)));
1428
1429         io.lockx.level = RAW_LOCK_LOCKX;
1430         io.lockx.in.file.fnum = fnum;
1431         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1432         io.lockx.in.timeout = 0;
1433         io.lockx.in.ulock_cnt = 0;
1434         io.lockx.in.lock_cnt = 1;
1435         lock[0].pid = cli->session->pid;
1436         lock[0].offset = 100;
1437         lock[0].count = 10;
1438         io.lockx.in.locks = &lock[0];
1439         status = smb_raw_lock(cli->tree, &io);
1440         CHECK_STATUS(status, NT_STATUS_OK);
1441
1442         start = time(NULL);
1443         io.lockx.in.timeout = t;
1444         req = smb_raw_lock_send(cli->tree, &io);
1445         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1446                        "Failed to setup timed lock (%s)\n", __location__));
1447
1448         io.lockx.in.timeout = 0;
1449         status = smb_raw_lock(cli->tree, &io);
1450         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1451
1452         status = smbcli_request_simple_recv(req);
1453         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1454
1455         delay = t / 1000;
1456         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1457                 delay /= 2;
1458         }
1459
1460         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1461                        "lock comes back to early timeout[%d] delay[%d]"
1462                        "(%s)\n", t, delay, __location__));
1463
1464         status = smb_raw_lock(cli->tree, &io);
1465         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1466
1467 done:
1468         smb_raw_exit(cli->session);
1469         smbcli_deltree(cli->tree, BASEDIR);
1470         return ret;
1471 }
1472
1473
1474 /*
1475   test LOCKING_ANDX_CHANGE_LOCKTYPE
1476 */
1477 static bool test_changetype(struct torture_context *tctx, 
1478                                                         struct smbcli_state *cli)
1479 {
1480         union smb_lock io;
1481         struct smb_lock_entry lock[2];
1482         NTSTATUS status;
1483         bool ret = true;
1484         int fnum;
1485         uint8_t c = 0;
1486         const char *fname = BASEDIR "\\test.txt";
1487
1488         if (!torture_setup_dir(cli, BASEDIR)) {
1489                 return false;
1490         }
1491
1492         torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1493         io.generic.level = RAW_LOCK_LOCKX;
1494         
1495         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1496         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1497                        "Failed to create %s - %s\n",
1498                        fname, smbcli_errstr(cli->tree)));
1499
1500         io.lockx.level = RAW_LOCK_LOCKX;
1501         io.lockx.in.file.fnum = fnum;
1502         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1503         io.lockx.in.timeout = 0;
1504         io.lockx.in.ulock_cnt = 0;
1505         io.lockx.in.lock_cnt = 1;
1506         lock[0].pid = cli->session->pid;
1507         lock[0].offset = 100;
1508         lock[0].count = 10;
1509         io.lockx.in.locks = &lock[0];
1510         status = smb_raw_lock(cli->tree, &io);
1511         CHECK_STATUS(status, NT_STATUS_OK);
1512
1513         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1514                 torture_result(tctx, TORTURE_FAIL,
1515                         "allowed write on read locked region (%s)\n", __location__);
1516                 ret = false;
1517                 goto done;
1518         }
1519
1520         /* windows server don't seem to support this */
1521         io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1522         status = smb_raw_lock(cli->tree, &io);
1523         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1524
1525         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1526                 torture_result(tctx, TORTURE_FAIL,
1527                         "allowed write after lock change (%s)\n", __location__);
1528                 ret = false;
1529                 goto done;
1530         }
1531
1532 done:
1533         smbcli_close(cli->tree, fnum);
1534         smb_raw_exit(cli->session);
1535         smbcli_deltree(cli->tree, BASEDIR);
1536         return ret;
1537 }
1538
1539 struct double_lock_test {
1540         struct smb_lock_entry lock1;
1541         struct smb_lock_entry lock2;
1542         NTSTATUS exp_status;
1543 };
1544
1545 /**
1546  * Tests zero byte locks.
1547  */
1548 static struct double_lock_test zero_byte_tests[] = {
1549         /* {pid, offset, count}, {pid, offset, count}, status */
1550
1551         /** First, takes a zero byte lock at offset 10. Then:
1552         *   - Taking 0 byte lock at 10 should succeed.
1553         *   - Taking 1 byte locks at 9,10,11 should succeed.
1554         *   - Taking 2 byte lock at 9 should fail.
1555         *   - Taking 2 byte lock at 10 should succeed.
1556         *   - Taking 3 byte lock at 9 should fail.
1557         */
1558         {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1559         {{1000, 10, 0}, {1001, 9, 1},  NT_STATUS_OK},
1560         {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1561         {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1562         {{1000, 10, 0}, {1001, 9, 2},  NT_STATUS_LOCK_NOT_GRANTED},
1563         {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1564         {{1000, 10, 0}, {1001, 9, 3},  NT_STATUS_LOCK_NOT_GRANTED},
1565
1566         /** Same, but opposite order. */
1567         {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1568         {{1001, 9, 1},  {1000, 10, 0}, NT_STATUS_OK},
1569         {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1570         {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1571         {{1001, 9, 2},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1572         {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1573         {{1001, 9, 3},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1574
1575         /** Zero zero case. */
1576         {{1000, 0, 0},  {1001, 0, 0},  NT_STATUS_OK},
1577 };
1578
1579 static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1580 {
1581         union smb_lock io;
1582         NTSTATUS status;
1583         bool ret = true;
1584         int fnum, i;
1585         const char *fname = BASEDIR "\\zero.txt";
1586
1587         torture_comment(tctx, "Testing zero length byte range locks:\n");
1588
1589         if (!torture_setup_dir(cli, BASEDIR)) {
1590                 return false;
1591         }
1592
1593         io.generic.level = RAW_LOCK_LOCKX;
1594
1595         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1596         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1597                        "Failed to create %s - %s\n",
1598                        fname, smbcli_errstr(cli->tree)));
1599
1600         /* Setup initial parameters */
1601         io.lockx.level = RAW_LOCK_LOCKX;
1602         io.lockx.in.file.fnum = fnum;
1603         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1604         io.lockx.in.timeout = 0;
1605
1606         /* Try every combination of locks in zero_byte_tests. The first lock is
1607          * assumed to succeed. The second lock may contend, depending on the
1608          * expected status. */
1609         for (i = 0;
1610              i < ARRAY_SIZE(zero_byte_tests);
1611              i++) {
1612                 torture_comment(tctx, "  ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1613                     zero_byte_tests[i].lock1.pid,
1614                     zero_byte_tests[i].lock1.offset,
1615                     zero_byte_tests[i].lock1.count,
1616                     zero_byte_tests[i].lock2.pid,
1617                     zero_byte_tests[i].lock2.offset,
1618                     zero_byte_tests[i].lock2.count,
1619                     nt_errstr(zero_byte_tests[i].exp_status));
1620
1621                 /* Lock both locks. */
1622                 io.lockx.in.ulock_cnt = 0;
1623                 io.lockx.in.lock_cnt = 1;
1624
1625                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1626                                                     &zero_byte_tests[i].lock1);
1627                 status = smb_raw_lock(cli->tree, &io);
1628                 CHECK_STATUS(status, NT_STATUS_OK);
1629
1630                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1631                                                     &zero_byte_tests[i].lock2);
1632                 status = smb_raw_lock(cli->tree, &io);
1633
1634                 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1635                         NT_STATUS_LOCK_NOT_GRANTED)) {
1636                         /* Allow either of the failure messages and keep going
1637                          * if we see the wrong status. */
1638                         CHECK_STATUS_OR_CONT(status,
1639                             NT_STATUS_LOCK_NOT_GRANTED,
1640                             NT_STATUS_FILE_LOCK_CONFLICT);
1641
1642                 } else {
1643                         CHECK_STATUS_CONT(status,
1644                             zero_byte_tests[i].exp_status);
1645                 }
1646
1647                 /* Unlock both locks. */
1648                 io.lockx.in.ulock_cnt = 1;
1649                 io.lockx.in.lock_cnt = 0;
1650
1651                 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1652                         status = smb_raw_lock(cli->tree, &io);
1653                         CHECK_STATUS(status, NT_STATUS_OK);
1654                 }
1655
1656                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1657                                                     &zero_byte_tests[i].lock1);
1658                 status = smb_raw_lock(cli->tree, &io);
1659                 CHECK_STATUS(status, NT_STATUS_OK);
1660         }
1661
1662 done:
1663         smbcli_close(cli->tree, fnum);
1664         smb_raw_exit(cli->session);
1665         smbcli_deltree(cli->tree, BASEDIR);
1666         return ret;
1667 }
1668
1669 static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1670 {
1671         union smb_lock io;
1672         NTSTATUS status;
1673         bool ret = true;
1674         int fnum1, fnum2;
1675         const char *fname = BASEDIR "\\unlock.txt";
1676         struct smb_lock_entry lock1;
1677         struct smb_lock_entry lock2;
1678
1679         torture_comment(tctx, "Testing LOCKX unlock:\n");
1680
1681         if (!torture_setup_dir(cli, BASEDIR)) {
1682                 return false;
1683         }
1684
1685         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1686         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1687                        "Failed to create %s - %s\n",
1688                        fname, smbcli_errstr(cli->tree)));
1689
1690         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1691         torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1692                        "Failed to create %s - %s\n",
1693                        fname, smbcli_errstr(cli->tree)));
1694
1695         /* Setup initial parameters */
1696         io.lockx.level = RAW_LOCK_LOCKX;
1697         io.lockx.in.timeout = 0;
1698
1699         lock1.pid = cli->session->pid;
1700         lock1.offset = 0;
1701         lock1.count = 10;
1702         lock2.pid = cli->session->pid - 1;
1703         lock2.offset = 0;
1704         lock2.count = 10;
1705
1706         /**
1707          * Take exclusive lock, then unlock it with a shared-unlock call.
1708          */
1709         torture_comment(tctx, "  taking exclusive lock.\n");
1710         io.lockx.in.ulock_cnt = 0;
1711         io.lockx.in.lock_cnt = 1;
1712         io.lockx.in.mode = 0;
1713         io.lockx.in.file.fnum = fnum1;
1714         io.lockx.in.locks = &lock1;
1715         status = smb_raw_lock(cli->tree, &io);
1716         CHECK_STATUS(status, NT_STATUS_OK);
1717
1718         torture_comment(tctx, "  unlock the exclusive with a shared unlock call.\n");
1719         io.lockx.in.ulock_cnt = 1;
1720         io.lockx.in.lock_cnt = 0;
1721         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1722         io.lockx.in.file.fnum = fnum1;
1723         io.lockx.in.locks = &lock1;
1724         status = smb_raw_lock(cli->tree, &io);
1725         CHECK_STATUS(status, NT_STATUS_OK);
1726
1727         torture_comment(tctx, "  try shared lock on pid2/fnum2, testing the unlock.\n");
1728         io.lockx.in.ulock_cnt = 0;
1729         io.lockx.in.lock_cnt = 1;
1730         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1731         io.lockx.in.file.fnum = fnum2;
1732         io.lockx.in.locks = &lock2;
1733         status = smb_raw_lock(cli->tree, &io);
1734         CHECK_STATUS(status, NT_STATUS_OK);
1735
1736         /**
1737          * Unlock a shared lock with an exclusive-unlock call.
1738          */
1739         torture_comment(tctx, "  unlock new shared lock with exclusive unlock call.\n");
1740         io.lockx.in.ulock_cnt = 1;
1741         io.lockx.in.lock_cnt = 0;
1742         io.lockx.in.mode = 0;
1743         io.lockx.in.file.fnum = fnum2;
1744         io.lockx.in.locks = &lock2;
1745         status = smb_raw_lock(cli->tree, &io);
1746         CHECK_STATUS(status, NT_STATUS_OK);
1747
1748         torture_comment(tctx, "  try exclusive lock on pid1, testing the unlock.\n");
1749         io.lockx.in.ulock_cnt = 0;
1750         io.lockx.in.lock_cnt = 1;
1751         io.lockx.in.mode = 0;
1752         io.lockx.in.file.fnum = fnum1;
1753         io.lockx.in.locks = &lock1;
1754         status = smb_raw_lock(cli->tree, &io);
1755         CHECK_STATUS(status, NT_STATUS_OK);
1756
1757         /* cleanup */
1758         io.lockx.in.ulock_cnt = 1;
1759         io.lockx.in.lock_cnt = 0;
1760         status = smb_raw_lock(cli->tree, &io);
1761         CHECK_STATUS(status, NT_STATUS_OK);
1762
1763         /**
1764          * Test unlocking of 0-byte locks.
1765          */
1766
1767         torture_comment(tctx, "  lock shared and exclusive 0-byte locks, testing that Windows "
1768             "always unlocks the exclusive first.\n");
1769         lock1.pid = cli->session->pid;
1770         lock1.offset = 10;
1771         lock1.count = 0;
1772         lock2.pid = cli->session->pid;
1773         lock2.offset = 5;
1774         lock2.count = 10;
1775         io.lockx.in.ulock_cnt = 0;
1776         io.lockx.in.lock_cnt = 1;
1777         io.lockx.in.file.fnum = fnum1;
1778         io.lockx.in.locks = &lock1;
1779
1780         /* lock 0-byte shared
1781          * Note: Order of the shared/exclusive locks doesn't matter. */
1782         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1783         status = smb_raw_lock(cli->tree, &io);
1784         CHECK_STATUS(status, NT_STATUS_OK);
1785
1786         /* lock 0-byte exclusive */
1787         io.lockx.in.mode = 0;
1788         status = smb_raw_lock(cli->tree, &io);
1789         CHECK_STATUS(status, NT_STATUS_OK);
1790
1791         /* test contention */
1792         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1793         io.lockx.in.locks = &lock2;
1794         io.lockx.in.file.fnum = fnum2;
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         /* unlock */
1800         io.lockx.in.ulock_cnt = 1;
1801         io.lockx.in.lock_cnt = 0;
1802         io.lockx.in.file.fnum = fnum1;
1803         io.lockx.in.locks = &lock1;
1804         status = smb_raw_lock(cli->tree, &io);
1805         CHECK_STATUS(status, NT_STATUS_OK);
1806
1807         /* test - can we take a shared lock? */
1808         io.lockx.in.ulock_cnt = 0;
1809         io.lockx.in.lock_cnt = 1;
1810         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1811         io.lockx.in.file.fnum = fnum2;
1812         io.lockx.in.locks = &lock2;
1813         status = smb_raw_lock(cli->tree, &io);
1814
1815         /* XXX Samba 3 will fail this test. This is temporary(because this isn't
1816          * new to Win7, it succeeds in WinXP too), until I can come to a
1817          * resolution as to whether Samba should support this or not. There is
1818          * code to preference unlocking exclusive locks before shared locks,
1819          * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1820         if (TARGET_IS_SAMBA3(tctx)) {
1821                 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1822                     NT_STATUS_FILE_LOCK_CONFLICT);
1823         } else {
1824                 CHECK_STATUS(status, NT_STATUS_OK);
1825         }
1826
1827         /* cleanup */
1828         io.lockx.in.ulock_cnt = 1;
1829         io.lockx.in.lock_cnt = 0;
1830         status = smb_raw_lock(cli->tree, &io);
1831
1832         /* XXX Same as above. */
1833         if (TARGET_IS_SAMBA3(tctx)) {
1834                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1835         } else {
1836                 CHECK_STATUS(status, NT_STATUS_OK);
1837         }
1838
1839         io.lockx.in.file.fnum = fnum1;
1840         io.lockx.in.locks = &lock1;
1841         status = smb_raw_lock(cli->tree, &io);
1842         CHECK_STATUS(status, NT_STATUS_OK);
1843
1844 done:
1845         smbcli_close(cli->tree, fnum1);
1846         smbcli_close(cli->tree, fnum2);
1847         smb_raw_exit(cli->session);
1848         smbcli_deltree(cli->tree, BASEDIR);
1849         return ret;
1850 }
1851
1852 static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1853 {
1854         union smb_lock io;
1855         NTSTATUS status;
1856         bool ret = true;
1857         int fnum1;
1858         const char *fname = BASEDIR "\\unlock_multiple.txt";
1859         struct smb_lock_entry lock1;
1860         struct smb_lock_entry lock2;
1861         struct smb_lock_entry locks[2];
1862
1863         torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1864
1865         if (!torture_setup_dir(cli, BASEDIR)) {
1866                 return false;
1867         }
1868
1869         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1870         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1871                        "Failed to create %s - %s\n",
1872                        fname, smbcli_errstr(cli->tree)));
1873
1874         /* Setup initial parameters */
1875         io.lockx.level = RAW_LOCK_LOCKX;
1876         io.lockx.in.timeout = 0;
1877
1878         lock1.pid = cli->session->pid;
1879         lock1.offset = 0;
1880         lock1.count = 10;
1881         lock2.pid = cli->session->pid;
1882         lock2.offset = 10;
1883         lock2.count = 10;
1884
1885         locks[0] = lock1;
1886         locks[1] = lock2;
1887
1888         io.lockx.in.file.fnum = fnum1;
1889         io.lockx.in.mode = 0; /* exclusive */
1890
1891         /** Test1: Take second lock, but not first. */
1892         torture_comment(tctx, "  unlock 2 locks, first one not locked. Expect no locks "
1893             "unlocked. \n");
1894
1895         io.lockx.in.ulock_cnt = 0;
1896         io.lockx.in.lock_cnt = 1;
1897         io.lockx.in.locks = &lock2;
1898         status = smb_raw_lock(cli->tree, &io);
1899         CHECK_STATUS(status, NT_STATUS_OK);
1900
1901         /* Try to unlock both locks. */
1902         io.lockx.in.ulock_cnt = 2;
1903         io.lockx.in.lock_cnt = 0;
1904         io.lockx.in.locks = locks;
1905
1906         status = smb_raw_lock(cli->tree, &io);
1907         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1908
1909         /* Second lock should not be unlocked. */
1910         io.lockx.in.ulock_cnt = 0;
1911         io.lockx.in.lock_cnt = 1;
1912         io.lockx.in.locks = &lock2;
1913         status = smb_raw_lock(cli->tree, &io);
1914         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1915
1916         /* cleanup */
1917         io.lockx.in.ulock_cnt = 1;
1918         io.lockx.in.lock_cnt = 0;
1919         io.lockx.in.locks = &lock2;
1920         status = smb_raw_lock(cli->tree, &io);
1921         CHECK_STATUS(status, NT_STATUS_OK);
1922
1923         /** Test2: Take first lock, but not second. */
1924         torture_comment(tctx, "  unlock 2 locks, second one not locked. Expect first lock "
1925             "unlocked.\n");
1926
1927         io.lockx.in.ulock_cnt = 0;
1928         io.lockx.in.lock_cnt = 1;
1929         io.lockx.in.locks = &lock1;
1930         status = smb_raw_lock(cli->tree, &io);
1931         CHECK_STATUS(status, NT_STATUS_OK);
1932
1933         /* Try to unlock both locks. */
1934         io.lockx.in.ulock_cnt = 2;
1935         io.lockx.in.lock_cnt = 0;
1936         io.lockx.in.locks = locks;
1937
1938         status = smb_raw_lock(cli->tree, &io);
1939         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1940
1941         /* First lock should be unlocked. */
1942         io.lockx.in.ulock_cnt = 0;
1943         io.lockx.in.lock_cnt = 1;
1944         io.lockx.in.locks = &lock1;
1945         status = smb_raw_lock(cli->tree, &io);
1946         CHECK_STATUS(status, NT_STATUS_OK);
1947
1948         /* cleanup */
1949         io.lockx.in.ulock_cnt = 1;
1950         io.lockx.in.lock_cnt = 0;
1951         io.lockx.in.locks = &lock1;
1952         status = smb_raw_lock(cli->tree, &io);
1953         CHECK_STATUS(status, NT_STATUS_OK);
1954
1955         /* Test3: Request 2 locks, second will contend.  What happens to the
1956          * first? */
1957         torture_comment(tctx, "  request 2 locks, second one will contend. "
1958            "Expect both to fail.\n");
1959
1960         /* Lock the second range */
1961         io.lockx.in.ulock_cnt = 0;
1962         io.lockx.in.lock_cnt = 1;
1963         io.lockx.in.locks = &lock2;
1964         status = smb_raw_lock(cli->tree, &io);
1965         CHECK_STATUS(status, NT_STATUS_OK);
1966
1967         /* Request both locks */
1968         io.lockx.in.ulock_cnt = 0;
1969         io.lockx.in.lock_cnt = 2;
1970         io.lockx.in.locks = locks;
1971
1972         status = smb_raw_lock(cli->tree, &io);
1973         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1974
1975         /* First lock should be unlocked. */
1976         io.lockx.in.ulock_cnt = 0;
1977         io.lockx.in.lock_cnt = 1;
1978         io.lockx.in.locks = &lock1;
1979         status = smb_raw_lock(cli->tree, &io);
1980         CHECK_STATUS(status, NT_STATUS_OK);
1981
1982         /* cleanup */
1983         io.lockx.in.ulock_cnt = 2;
1984         io.lockx.in.lock_cnt = 0;
1985         io.lockx.in.locks = locks;
1986         status = smb_raw_lock(cli->tree, &io);
1987         CHECK_STATUS(status, NT_STATUS_OK);
1988
1989         /* Test4: Request unlock and lock. The lock contends, is the unlock
1990          * then re-locked? */
1991         torture_comment(tctx, "  request unlock and lock, second one will "
1992            "contend. Expect the unlock to succeed.\n");
1993
1994         /* Lock both ranges */
1995         io.lockx.in.ulock_cnt = 0;
1996         io.lockx.in.lock_cnt = 2;
1997         io.lockx.in.locks = locks;
1998         status = smb_raw_lock(cli->tree, &io);
1999         CHECK_STATUS(status, NT_STATUS_OK);
2000
2001         /* Attempt to unlock the first range and lock the second */
2002         io.lockx.in.ulock_cnt = 1;
2003         io.lockx.in.lock_cnt = 1;
2004         io.lockx.in.locks = locks;
2005         status = smb_raw_lock(cli->tree, &io);
2006         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2007
2008         /* The first lock should've been unlocked */
2009         io.lockx.in.ulock_cnt = 0;
2010         io.lockx.in.lock_cnt = 1;
2011         io.lockx.in.locks = &lock1;
2012         status = smb_raw_lock(cli->tree, &io);
2013         CHECK_STATUS(status, NT_STATUS_OK);
2014
2015         /* cleanup */
2016         io.lockx.in.ulock_cnt = 2;
2017         io.lockx.in.lock_cnt = 0;
2018         io.lockx.in.locks = locks;
2019         status = smb_raw_lock(cli->tree, &io);
2020         CHECK_STATUS(status, NT_STATUS_OK);
2021
2022 done:
2023         smbcli_close(cli->tree, fnum1);
2024         smb_raw_exit(cli->session);
2025         smbcli_deltree(cli->tree, BASEDIR);
2026         return ret;
2027 }
2028
2029 /**
2030  * torture_locktest5 covers stacking pretty well, but its missing two tests:
2031  * - stacking an exclusive on top of shared fails
2032  * - stacking two exclusives fail
2033  */
2034 static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
2035 {
2036         union smb_lock io;
2037         NTSTATUS status;
2038         bool ret = true;
2039         int fnum1;
2040         const char *fname = BASEDIR "\\stacking.txt";
2041         struct smb_lock_entry lock1;
2042         struct smb_lock_entry lock2;
2043
2044         torture_comment(tctx, "Testing stacking:\n");
2045
2046         if (!torture_setup_dir(cli, BASEDIR)) {
2047                 return false;
2048         }
2049
2050         io.generic.level = RAW_LOCK_LOCKX;
2051
2052         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2053         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2054                        "Failed to create %s - %s\n",
2055                        fname, smbcli_errstr(cli->tree)));
2056
2057         /* Setup initial parameters */
2058         io.lockx.level = RAW_LOCK_LOCKX;
2059         io.lockx.in.timeout = 0;
2060
2061         lock1.pid = cli->session->pid;
2062         lock1.offset = 0;
2063         lock1.count = 10;
2064         lock2.pid = cli->session->pid - 1;
2065         lock2.offset = 0;
2066         lock2.count = 10;
2067
2068         /**
2069          * Try to take a shared lock, then stack an exclusive.
2070          */
2071         torture_comment(tctx, "  stacking an exclusive on top of a shared lock fails.\n");
2072         io.lockx.in.file.fnum = fnum1;
2073         io.lockx.in.locks = &lock1;
2074
2075         io.lockx.in.ulock_cnt = 0;
2076         io.lockx.in.lock_cnt = 1;
2077         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
2078         status = smb_raw_lock(cli->tree, &io);
2079         CHECK_STATUS(status, NT_STATUS_OK);
2080
2081         io.lockx.in.ulock_cnt = 0;
2082         io.lockx.in.lock_cnt = 1;
2083         io.lockx.in.mode = 0;
2084         status = smb_raw_lock(cli->tree, &io);
2085         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2086             NT_STATUS_FILE_LOCK_CONFLICT);
2087
2088         /* cleanup */
2089         io.lockx.in.ulock_cnt = 1;
2090         io.lockx.in.lock_cnt = 0;
2091         status = smb_raw_lock(cli->tree, &io);
2092         CHECK_STATUS(status, NT_STATUS_OK);
2093
2094         /**
2095          * Prove that two exclusive locks do not stack.
2096          */
2097         torture_comment(tctx, "  two exclusive locks do not stack.\n");
2098         io.lockx.in.ulock_cnt = 0;
2099         io.lockx.in.lock_cnt = 1;
2100         io.lockx.in.mode = 0;
2101         status = smb_raw_lock(cli->tree, &io);
2102         CHECK_STATUS(status, NT_STATUS_OK);
2103         status = smb_raw_lock(cli->tree, &io);
2104         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2105             NT_STATUS_FILE_LOCK_CONFLICT);
2106
2107         /* cleanup */
2108         io.lockx.in.ulock_cnt = 1;
2109         io.lockx.in.lock_cnt = 0;
2110         status = smb_raw_lock(cli->tree, &io);
2111         CHECK_STATUS(status, NT_STATUS_OK);
2112
2113 done:
2114         smbcli_close(cli->tree, fnum1);
2115         smb_raw_exit(cli->session);
2116         smbcli_deltree(cli->tree, BASEDIR);
2117         return ret;
2118 }
2119
2120 /**
2121  * Test how 0-byte read requests contend with byte range locks
2122  */
2123 static bool test_zerobyteread(struct torture_context *tctx,
2124                               struct smbcli_state *cli)
2125 {
2126         union smb_lock io;
2127         union smb_read rd;
2128         NTSTATUS status;
2129         bool ret = true;
2130         int fnum1, fnum2;
2131         const char *fname = BASEDIR "\\zerobyteread.txt";
2132         struct smb_lock_entry lock1;
2133         uint8_t c = 1;
2134
2135         if (!torture_setup_dir(cli, BASEDIR)) {
2136                 return false;
2137         }
2138
2139         io.generic.level = RAW_LOCK_LOCKX;
2140
2141         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2142         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2143                        "Failed to create %s - %s\n",
2144                        fname, smbcli_errstr(cli->tree)));
2145
2146         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2147         torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
2148                        "Failed to create %s - %s\n",
2149                        fname, smbcli_errstr(cli->tree)));
2150
2151         /* Setup initial parameters */
2152         io.lockx.level = RAW_LOCK_LOCKX;
2153         io.lockx.in.timeout = 0;
2154
2155         lock1.pid = cli->session->pid;
2156         lock1.offset = 0;
2157         lock1.count = 10;
2158
2159         ZERO_STRUCT(rd);
2160         rd.readx.level = RAW_READ_READX;
2161
2162         torture_comment(tctx, "Testing zero byte read on lock range:\n");
2163
2164         /* Take an exclusive lock */
2165         torture_comment(tctx, "  taking exclusive lock.\n");
2166         io.lockx.in.ulock_cnt = 0;
2167         io.lockx.in.lock_cnt = 1;
2168         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2169         io.lockx.in.file.fnum = fnum1;
2170         io.lockx.in.locks = &lock1;
2171         status = smb_raw_lock(cli->tree, &io);
2172         CHECK_STATUS(status, NT_STATUS_OK);
2173
2174         /* Try a zero byte read */
2175         torture_comment(tctx, "  reading 0 bytes.\n");
2176         rd.readx.in.file.fnum = fnum2;
2177         rd.readx.in.offset    = 5;
2178         rd.readx.in.mincnt    = 0;
2179         rd.readx.in.maxcnt    = 0;
2180         rd.readx.in.remaining = 0;
2181         rd.readx.in.read_for_execute = false;
2182         rd.readx.out.data     = &c;
2183         status = smb_raw_read(cli->tree, &rd);
2184         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2185                                       "zero byte read did not return 0 bytes");
2186         CHECK_STATUS(status, NT_STATUS_OK);
2187
2188         /* Unlock lock */
2189         io.lockx.in.ulock_cnt = 1;
2190         io.lockx.in.lock_cnt = 0;
2191         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2192         io.lockx.in.file.fnum = fnum1;
2193         io.lockx.in.locks = &lock1;
2194         status = smb_raw_lock(cli->tree, &io);
2195         CHECK_STATUS(status, NT_STATUS_OK);
2196
2197         torture_comment(tctx, "Testing zero byte read on zero byte lock "
2198                               "range:\n");
2199
2200         /* Take an exclusive lock */
2201         torture_comment(tctx, "  taking exclusive 0-byte lock.\n");
2202         io.lockx.in.ulock_cnt = 0;
2203         io.lockx.in.lock_cnt = 1;
2204         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2205         io.lockx.in.file.fnum = fnum1;
2206         io.lockx.in.locks = &lock1;
2207         lock1.offset = 5;
2208         lock1.count = 0;
2209         status = smb_raw_lock(cli->tree, &io);
2210         CHECK_STATUS(status, NT_STATUS_OK);
2211
2212         /* Try a zero byte read before the lock */
2213         torture_comment(tctx, "  reading 0 bytes before the lock.\n");
2214         rd.readx.in.file.fnum = fnum2;
2215         rd.readx.in.offset    = 4;
2216         rd.readx.in.mincnt    = 0;
2217         rd.readx.in.maxcnt    = 0;
2218         rd.readx.in.remaining = 0;
2219         rd.readx.in.read_for_execute = false;
2220         rd.readx.out.data     = &c;
2221         status = smb_raw_read(cli->tree, &rd);
2222         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2223                                       "zero byte read did not return 0 bytes");
2224         CHECK_STATUS(status, NT_STATUS_OK);
2225
2226         /* Try a zero byte read on the lock */
2227         torture_comment(tctx, "  reading 0 bytes on the lock.\n");
2228         rd.readx.in.file.fnum = fnum2;
2229         rd.readx.in.offset    = 5;
2230         rd.readx.in.mincnt    = 0;
2231         rd.readx.in.maxcnt    = 0;
2232         rd.readx.in.remaining = 0;
2233         rd.readx.in.read_for_execute = false;
2234         rd.readx.out.data     = &c;
2235         status = smb_raw_read(cli->tree, &rd);
2236         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2237                                       "zero byte read did not return 0 bytes");
2238         CHECK_STATUS(status, NT_STATUS_OK);
2239
2240         /* Try a zero byte read after the lock */
2241         torture_comment(tctx, "  reading 0 bytes after the lock.\n");
2242         rd.readx.in.file.fnum = fnum2;
2243         rd.readx.in.offset    = 6;
2244         rd.readx.in.mincnt    = 0;
2245         rd.readx.in.maxcnt    = 0;
2246         rd.readx.in.remaining = 0;
2247         rd.readx.in.read_for_execute = false;
2248         rd.readx.out.data     = &c;
2249         status = smb_raw_read(cli->tree, &rd);
2250         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2251                                       "zero byte read did not return 0 bytes");
2252         CHECK_STATUS(status, NT_STATUS_OK);
2253
2254         /* Unlock lock */
2255         io.lockx.in.ulock_cnt = 1;
2256         io.lockx.in.lock_cnt = 0;
2257         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2258         io.lockx.in.file.fnum = fnum1;
2259         io.lockx.in.locks = &lock1;
2260         status = smb_raw_lock(cli->tree, &io);
2261         CHECK_STATUS(status, NT_STATUS_OK);
2262
2263 done:
2264         smbcli_close(cli->tree, fnum1);
2265         smbcli_close(cli->tree, fnum2);
2266         smb_raw_exit(cli->session);
2267         smbcli_deltree(cli->tree, BASEDIR);
2268         return ret;
2269 }
2270
2271 /*
2272    basic testing of lock calls
2273 */
2274 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
2275 {
2276         struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
2277
2278         torture_suite_add_1smb_test(suite, "lockx", test_lockx);
2279         torture_suite_add_1smb_test(suite, "lock", test_lock);
2280         torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
2281         torture_suite_add_1smb_test(suite, "async", test_async);
2282         torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
2283         torture_suite_add_1smb_test(suite, "changetype", test_changetype);
2284
2285         torture_suite_add_1smb_test(suite, "stacking", test_stacking);
2286         torture_suite_add_1smb_test(suite, "unlock", test_unlock);
2287         torture_suite_add_1smb_test(suite, "multiple_unlock",
2288             test_multiple_unlock);
2289         torture_suite_add_1smb_test(suite, "zerobytelocks",
2290             test_zerobytelocks);
2291         torture_suite_add_1smb_test(suite, "zerobyteread",
2292             test_zerobyteread);
2293
2294         return suite;
2295 }