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