s4/torture: add test for zero byte read contention with byte range locks
[gd/samba-autobuild/.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.locks = &lock[1];
647         status = smb_raw_lock(cli->tree, &io);
648         CHECK_STATUS(status, NT_STATUS_OK);
649
650         torture_comment(tctx, "testing cancel by unlock\n");
651         io.lockx.in.ulock_cnt = 0;
652         io.lockx.in.lock_cnt = 1;
653         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
654         io.lockx.in.timeout = 0;
655         io.lockx.in.locks = &lock[0];
656         status = smb_raw_lock(cli->tree, &io);
657         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
658
659         io.lockx.in.timeout = 5000;
660         req = smb_raw_lock_send(cli->tree, &io);
661         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
662                        "Failed to setup timed lock (%s)\n", __location__));
663
664         io.lockx.in.ulock_cnt = 1;
665         io.lockx.in.lock_cnt = 0;
666         status = smb_raw_lock(cli->tree, &io);
667         CHECK_STATUS(status, NT_STATUS_OK);
668
669         t = time(NULL);
670         status = smbcli_request_simple_recv(req);
671         CHECK_STATUS(status, NT_STATUS_OK);
672
673         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
674                        "lock cancel by unlock was not immediate (%s) - took %d secs\n",
675                        __location__, (int)(time(NULL)-t)));
676
677         torture_comment(tctx, "testing cancel by close\n");
678         io.lockx.in.ulock_cnt = 0;
679         io.lockx.in.lock_cnt = 1;
680         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
681         io.lockx.in.timeout = 0;
682         status = smb_raw_lock(cli->tree, &io);
683         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
684
685         t = time(NULL);
686         io.lockx.in.timeout = 10000;
687         req = smb_raw_lock_send(cli->tree, &io);
688         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
689                        "Failed to setup timed lock (%s)\n", __location__));
690
691         status = smbcli_close(cli->tree, fnum);
692         CHECK_STATUS(status, NT_STATUS_OK);
693
694         status = smbcli_request_simple_recv(req);
695         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
696
697         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
698                        "lock cancel by close was not immediate (%s)\n", __location__));
699
700         torture_comment(tctx, "create a new sessions\n");
701         session = smbcli_session_init(cli->transport, tctx, false, options);
702         setup.in.sesskey = cli->transport->negotiate.sesskey;
703         setup.in.capabilities = cli->transport->negotiate.capabilities;
704         setup.in.workgroup = lp_workgroup(tctx->lp_ctx);
705         setup.in.credentials = cmdline_credentials;
706         setup.in.gensec_settings = lp_gensec_settings(tctx, tctx->lp_ctx);
707         status = smb_composite_sesssetup(session, &setup);
708         CHECK_STATUS(status, NT_STATUS_OK);
709         session->vuid = setup.out.vuid;
710
711         torture_comment(tctx, "create new tree context\n");
712         share = torture_setting_string(tctx, "share", NULL);
713         host  = torture_setting_string(tctx, "host", NULL);
714         tree = smbcli_tree_init(session, tctx, false);
715         tcon.generic.level = RAW_TCON_TCONX;
716         tcon.tconx.in.flags = 0;
717         tcon.tconx.in.password = data_blob(NULL, 0);
718         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
719         tcon.tconx.in.device = "A:";
720         status = smb_raw_tcon(tree, tctx, &tcon);
721         CHECK_STATUS(status, NT_STATUS_OK);
722         tree->tid = tcon.tconx.out.tid;
723
724         torture_comment(tctx, "testing cancel by exit\n");
725         fname = BASEDIR "\\test_exit.txt";
726         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
727         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
728                        "Failed to reopen %s - %s\n",
729                        fname, smbcli_errstr(tree)));
730
731         io.lockx.level = RAW_LOCK_LOCKX;
732         io.lockx.in.file.fnum = fnum;
733         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
734         io.lockx.in.timeout = 0;
735         io.lockx.in.ulock_cnt = 0;
736         io.lockx.in.lock_cnt = 1;
737         lock[0].pid = session->pid;
738         lock[0].offset = 100;
739         lock[0].count = 10;
740         io.lockx.in.locks = &lock[0];
741         status = smb_raw_lock(tree, &io);
742         CHECK_STATUS(status, NT_STATUS_OK);
743
744         io.lockx.in.ulock_cnt = 0;
745         io.lockx.in.lock_cnt = 1;
746         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
747         io.lockx.in.timeout = 0;
748         status = smb_raw_lock(tree, &io);
749         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
750
751         io.lockx.in.timeout = 10000;
752         t = time(NULL);
753         req = smb_raw_lock_send(tree, &io);
754         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
755                        "Failed to setup timed lock (%s)\n", __location__));
756
757         status = smb_raw_exit(session);
758         CHECK_STATUS(status, NT_STATUS_OK);
759
760         status = smbcli_request_simple_recv(req);
761         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
762
763         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
764                        "lock cancel by exit was not immediate (%s)\n", __location__));
765
766         torture_comment(tctx, "testing cancel by ulogoff\n");
767         fname = BASEDIR "\\test_ulogoff.txt";
768         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
769         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
770                        "Failed to reopen %s - %s\n",
771                        fname, smbcli_errstr(tree)));
772
773         io.lockx.level = RAW_LOCK_LOCKX;
774         io.lockx.in.file.fnum = fnum;
775         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
776         io.lockx.in.timeout = 0;
777         io.lockx.in.ulock_cnt = 0;
778         io.lockx.in.lock_cnt = 1;
779         lock[0].pid = session->pid;
780         lock[0].offset = 100;
781         lock[0].count = 10;
782         io.lockx.in.locks = &lock[0];
783         status = smb_raw_lock(tree, &io);
784         CHECK_STATUS(status, NT_STATUS_OK);
785
786         io.lockx.in.ulock_cnt = 0;
787         io.lockx.in.lock_cnt = 1;
788         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
789         io.lockx.in.timeout = 0;
790         status = smb_raw_lock(tree, &io);
791         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
792
793         io.lockx.in.timeout = 10000;
794         t = time(NULL);
795         req = smb_raw_lock_send(tree, &io);
796         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
797                        "Failed to setup timed lock (%s)\n", __location__));
798
799         status = smb_raw_ulogoff(session);
800         CHECK_STATUS(status, NT_STATUS_OK);
801
802         status = smbcli_request_simple_recv(req);
803         if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
804                 torture_result(tctx, TORTURE_FAIL,
805                         "lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n",
806                         nt_errstr(status));
807                 smb_tree_disconnect(tree);
808                 smb_raw_exit(session);
809                 goto done;
810         }
811         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
812
813         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
814                        "lock cancel by ulogoff was not immediate (%s)\n", __location__));
815
816         torture_comment(tctx, "testing cancel by tdis\n");
817         tree->session = cli->session;
818
819         fname = BASEDIR "\\test_tdis.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 = cli->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         status = smb_raw_lock(tree, &io);
839         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
840
841         io.lockx.in.timeout = 10000;
842         t = time(NULL);
843         req = smb_raw_lock_send(tree, &io);
844         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
845                        "Failed to setup timed lock (%s)\n", __location__));
846
847         status = smb_tree_disconnect(tree);
848         CHECK_STATUS(status, NT_STATUS_OK);
849
850         status = smbcli_request_simple_recv(req);
851         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
852
853         torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
854                        "lock cancel by tdis was not immediate (%s)\n", __location__));
855
856 done:
857         smb_raw_exit(cli->session);
858         smbcli_deltree(cli->tree, BASEDIR);
859         return ret;
860 }
861
862 /*
863   test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
864 */
865 static bool test_errorcode(struct torture_context *tctx, 
866                                                    struct smbcli_state *cli)
867 {
868         union smb_lock io;
869         union smb_open op;
870         struct smb_lock_entry lock[2];
871         NTSTATUS status;
872         bool ret = true;
873         int fnum, fnum2;
874         const char *fname;
875         struct smbcli_request *req;
876         time_t start;
877         int t;
878         int delay;
879         uint16_t deny_mode = 0;
880
881         if (!torture_setup_dir(cli, BASEDIR)) {
882                 return false;
883         }
884
885         torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
886
887         torture_comment(tctx, "testing with timeout = 0\n");
888         fname = BASEDIR "\\test0.txt";
889         t = 0;
890
891         /*
892          * the first run is with t = 0,
893          * the second with t > 0 (=1)
894          */
895 next_run:
896         /*
897          * use the DENY_DOS mode, that creates two fnum's of one low-level
898          * file handle, this demonstrates that the cache is per fnum, not
899          * per file handle
900          */
901         if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
902             deny_mode = OPENX_MODE_DENY_DOS;
903         else
904             deny_mode = OPENX_MODE_DENY_NONE;
905
906         op.openx.level = RAW_OPEN_OPENX;
907         op.openx.in.fname = fname;
908         op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
909         op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
910         op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
911         op.openx.in.search_attrs = 0;
912         op.openx.in.file_attrs = 0;
913         op.openx.in.write_time = 0;
914         op.openx.in.size = 0;
915         op.openx.in.timeout = 0;
916
917         status = smb_raw_open(cli->tree, tctx, &op);
918         CHECK_STATUS(status, NT_STATUS_OK);
919         fnum = op.openx.out.file.fnum;
920
921         status = smb_raw_open(cli->tree, tctx, &op);
922         CHECK_STATUS(status, NT_STATUS_OK);
923         fnum2 = op.openx.out.file.fnum;
924
925         io.lockx.level = RAW_LOCK_LOCKX;
926         io.lockx.in.file.fnum = fnum;
927         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
928         io.lockx.in.timeout = t;
929         io.lockx.in.ulock_cnt = 0;
930         io.lockx.in.lock_cnt = 1;
931         lock[0].pid = cli->session->pid;
932         lock[0].offset = 100;
933         lock[0].count = 10;
934         io.lockx.in.locks = &lock[0];
935         status = smb_raw_lock(cli->tree, &io);
936         CHECK_STATUS(status, NT_STATUS_OK);
937
938         /*
939          * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
940          * this also demonstrates that the error code cache is per file handle
941          * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
942          */
943         io.lockx.in.file.fnum = fnum2;
944         status = smb_raw_lock(cli->tree, &io);
945         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
946
947         io.lockx.in.file.fnum = fnum;
948         status = smb_raw_lock(cli->tree, &io);
949         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
950
951         /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
952         io.lockx.in.file.fnum = fnum;
953         status = smb_raw_lock(cli->tree, &io);
954         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
955
956         io.lockx.in.file.fnum = fnum2;
957         status = smb_raw_lock(cli->tree, &io);
958         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
959
960         io.lockx.in.file.fnum = fnum;
961         status = smb_raw_lock(cli->tree, &io);
962         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
963
964         io.lockx.in.file.fnum = fnum2;
965         status = smb_raw_lock(cli->tree, &io);
966         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
967
968         /* demonstrate that the smbpid doesn't matter */
969         lock[0].pid++;
970         io.lockx.in.file.fnum = fnum;
971         status = smb_raw_lock(cli->tree, &io);
972         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
973
974         io.lockx.in.file.fnum = fnum2;
975         status = smb_raw_lock(cli->tree, &io);
976         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
977         lock[0].pid--;
978
979         /* 
980          * demonstrate the a successful lock with count = 0 and the same offset,
981          * doesn't reset the error cache
982          */
983         lock[0].offset = 100;
984         lock[0].count = 0;
985         io.lockx.in.file.fnum = fnum;
986         status = smb_raw_lock(cli->tree, &io);
987         CHECK_STATUS(status, NT_STATUS_OK);
988
989         io.lockx.in.file.fnum = fnum2;
990         status = smb_raw_lock(cli->tree, &io);
991         CHECK_STATUS(status, NT_STATUS_OK);
992
993         lock[0].offset = 100;
994         lock[0].count = 10;
995         io.lockx.in.file.fnum = fnum;
996         status = smb_raw_lock(cli->tree, &io);
997         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
998
999         io.lockx.in.file.fnum = fnum2;
1000         status = smb_raw_lock(cli->tree, &io);
1001         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1002
1003         /* 
1004          * demonstrate the a successful lock with count = 0 and outside the locked range,
1005          * doesn't reset the error cache
1006          */
1007         lock[0].offset = 110;
1008         lock[0].count = 0;
1009         io.lockx.in.file.fnum = fnum;
1010         status = smb_raw_lock(cli->tree, &io);
1011         CHECK_STATUS(status, NT_STATUS_OK);
1012
1013         io.lockx.in.file.fnum = fnum2;
1014         status = smb_raw_lock(cli->tree, &io);
1015         CHECK_STATUS(status, NT_STATUS_OK);
1016
1017         lock[0].offset = 100;
1018         lock[0].count = 10;
1019         io.lockx.in.file.fnum = fnum;
1020         status = smb_raw_lock(cli->tree, &io);
1021         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1022
1023         io.lockx.in.file.fnum = fnum2;
1024         status = smb_raw_lock(cli->tree, &io);
1025         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1026
1027         lock[0].offset = 99;
1028         lock[0].count = 0;
1029         io.lockx.in.file.fnum = fnum;
1030         status = smb_raw_lock(cli->tree, &io);
1031         CHECK_STATUS(status, NT_STATUS_OK);
1032
1033         io.lockx.in.file.fnum = fnum2;
1034         status = smb_raw_lock(cli->tree, &io);
1035         CHECK_STATUS(status, NT_STATUS_OK);
1036
1037         lock[0].offset = 100;
1038         lock[0].count = 10;
1039         io.lockx.in.file.fnum = fnum;
1040         status = smb_raw_lock(cli->tree, &io);
1041         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1042
1043         io.lockx.in.file.fnum = fnum2;
1044         status = smb_raw_lock(cli->tree, &io);
1045         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1046
1047         /* demonstrate that a changing count doesn't reset the error cache */
1048         lock[0].offset = 100;
1049         lock[0].count = 5;
1050         io.lockx.in.file.fnum = fnum;
1051         status = smb_raw_lock(cli->tree, &io);
1052         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1053
1054         io.lockx.in.file.fnum = fnum2;
1055         status = smb_raw_lock(cli->tree, &io);
1056         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1057
1058         lock[0].offset = 100;
1059         lock[0].count = 15;
1060         io.lockx.in.file.fnum = fnum;
1061         status = smb_raw_lock(cli->tree, &io);
1062         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1063
1064         io.lockx.in.file.fnum = fnum2;
1065         status = smb_raw_lock(cli->tree, &io);
1066         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1067
1068         /* 
1069          * demonstrate the a lock with count = 0 and inside the locked range,
1070          * fails and resets the error cache
1071          */
1072         lock[0].offset = 101;
1073         lock[0].count = 0;
1074         io.lockx.in.file.fnum = fnum;
1075         status = smb_raw_lock(cli->tree, &io);
1076         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1077         status = smb_raw_lock(cli->tree, &io);
1078         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1079
1080         io.lockx.in.file.fnum = fnum2;
1081         status = smb_raw_lock(cli->tree, &io);
1082         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1083         status = smb_raw_lock(cli->tree, &io);
1084         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1085
1086         lock[0].offset = 100;
1087         lock[0].count = 10;
1088         io.lockx.in.file.fnum = fnum;
1089         status = smb_raw_lock(cli->tree, &io);
1090         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1091         status = smb_raw_lock(cli->tree, &io);
1092         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1093
1094         io.lockx.in.file.fnum = fnum2;
1095         status = smb_raw_lock(cli->tree, &io);
1096         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1097         status = smb_raw_lock(cli->tree, &io);
1098         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1099
1100         /* demonstrate the a changing offset, resets the error cache */
1101         lock[0].offset = 105;
1102         lock[0].count = 10;
1103         io.lockx.in.file.fnum = fnum;
1104         status = smb_raw_lock(cli->tree, &io);
1105         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1106         status = smb_raw_lock(cli->tree, &io);
1107         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1108
1109         io.lockx.in.file.fnum = fnum2;
1110         status = smb_raw_lock(cli->tree, &io);
1111         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1112         status = smb_raw_lock(cli->tree, &io);
1113         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1114
1115         lock[0].offset = 100;
1116         lock[0].count = 10;
1117         io.lockx.in.file.fnum = fnum;
1118         status = smb_raw_lock(cli->tree, &io);
1119         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1120         status = smb_raw_lock(cli->tree, &io);
1121         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1122
1123         io.lockx.in.file.fnum = fnum2;
1124         status = smb_raw_lock(cli->tree, &io);
1125         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1126         status = smb_raw_lock(cli->tree, &io);
1127         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1128
1129         lock[0].offset = 95;
1130         lock[0].count = 9;
1131         io.lockx.in.file.fnum = fnum;
1132         status = smb_raw_lock(cli->tree, &io);
1133         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
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, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1140         status = smb_raw_lock(cli->tree, &io);
1141         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1142
1143         lock[0].offset = 100;
1144         lock[0].count = 10;
1145         io.lockx.in.file.fnum = fnum;
1146         status = smb_raw_lock(cli->tree, &io);
1147         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1148         status = smb_raw_lock(cli->tree, &io);
1149         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1150
1151         io.lockx.in.file.fnum = fnum2;
1152         status = smb_raw_lock(cli->tree, &io);
1153         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1154         status = smb_raw_lock(cli->tree, &io);
1155         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1156
1157         /* 
1158          * demonstrate the a successful lock in a different range, 
1159          * doesn't reset the cache, the failing lock on the 2nd handle
1160          * resets the cache
1161          */
1162         lock[0].offset = 120;
1163         lock[0].count = 15;
1164         io.lockx.in.file.fnum = fnum;
1165         status = smb_raw_lock(cli->tree, &io);
1166         CHECK_STATUS(status, NT_STATUS_OK);
1167
1168         io.lockx.in.file.fnum = fnum2;
1169         status = smb_raw_lock(cli->tree, &io);
1170         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1171
1172         lock[0].offset = 100;
1173         lock[0].count = 10;
1174         io.lockx.in.file.fnum = fnum;
1175         status = smb_raw_lock(cli->tree, &io);
1176         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1177         status = smb_raw_lock(cli->tree, &io);
1178         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1179
1180         io.lockx.in.file.fnum = fnum2;
1181         status = smb_raw_lock(cli->tree, &io);
1182         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1183         status = smb_raw_lock(cli->tree, &io);
1184         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1185
1186         /* end of the loop */
1187         if (t == 0) {
1188                 smb_raw_exit(cli->session);
1189                 t = 1;
1190                 torture_comment(tctx, "testing with timeout > 0 (=%d)\n",
1191                                 t);
1192                 fname = BASEDIR "\\test1.txt";
1193                 goto next_run;
1194         }
1195
1196         t = 4000;
1197         torture_comment(tctx, "testing special cases with timeout > 0 (=%d)\n",
1198                         t);
1199
1200         /*
1201          * the following 3 test sections demonstrate that
1202          * the cache is only set when the error is reported
1203          * to the client (after the timeout went by)
1204          */
1205         smb_raw_exit(cli->session);
1206         torture_comment(tctx, "testing a conflict while a lock is pending\n");
1207         fname = BASEDIR "\\test2.txt";
1208         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1209         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1210                        "Failed to reopen %s - %s\n",
1211                        fname, smbcli_errstr(cli->tree)));
1212
1213         io.lockx.level = RAW_LOCK_LOCKX;
1214         io.lockx.in.file.fnum = fnum;
1215         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1216         io.lockx.in.timeout = 0;
1217         io.lockx.in.ulock_cnt = 0;
1218         io.lockx.in.lock_cnt = 1;
1219         lock[0].pid = cli->session->pid;
1220         lock[0].offset = 100;
1221         lock[0].count = 10;
1222         io.lockx.in.locks = &lock[0];
1223         status = smb_raw_lock(cli->tree, &io);
1224         CHECK_STATUS(status, NT_STATUS_OK);
1225
1226         start = time(NULL);
1227         io.lockx.in.timeout = t;
1228         req = smb_raw_lock_send(cli->tree, &io);
1229         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1230                        "Failed to setup timed lock (%s)\n", __location__));
1231
1232         io.lockx.in.timeout = 0;
1233         lock[0].offset = 105;
1234         lock[0].count = 10;
1235         status = smb_raw_lock(cli->tree, &io);
1236         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1237
1238         status = smbcli_request_simple_recv(req);
1239         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1240
1241         delay = t / 1000;
1242         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1243                 delay /= 2;
1244         }
1245
1246         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1247                        "lock comes back to early timeout[%d] delay[%d]"
1248                        "(%s)\n", t, delay, __location__));
1249
1250         status = smb_raw_lock(cli->tree, &io);
1251         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1252
1253         smbcli_close(cli->tree, fnum);
1254         fname = BASEDIR "\\test3.txt";
1255         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1256         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1257                        "Failed to reopen %s - %s\n",
1258                        fname, smbcli_errstr(cli->tree)));
1259
1260         io.lockx.level = RAW_LOCK_LOCKX;
1261         io.lockx.in.file.fnum = fnum;
1262         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1263         io.lockx.in.timeout = 0;
1264         io.lockx.in.ulock_cnt = 0;
1265         io.lockx.in.lock_cnt = 1;
1266         lock[0].pid = cli->session->pid;
1267         lock[0].offset = 100;
1268         lock[0].count = 10;
1269         io.lockx.in.locks = &lock[0];
1270         status = smb_raw_lock(cli->tree, &io);
1271         CHECK_STATUS(status, NT_STATUS_OK);
1272
1273         start = time(NULL);
1274         io.lockx.in.timeout = t;
1275         req = smb_raw_lock_send(cli->tree, &io);
1276         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1277                        "Failed to setup timed lock (%s)\n", __location__));
1278
1279         io.lockx.in.timeout = 0;
1280         lock[0].offset = 105;
1281         lock[0].count = 10;
1282         status = smb_raw_lock(cli->tree, &io);
1283         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1284
1285         status = smbcli_request_simple_recv(req);
1286         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1287
1288         delay = t / 1000;
1289         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1290                 delay /= 2;
1291         }
1292
1293         torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1294                        "lock comes back to early timeout[%d] delay[%d]"
1295                        "(%s)\n", t, delay, __location__));
1296
1297         lock[0].offset = 100;
1298         lock[0].count = 10;
1299         status = smb_raw_lock(cli->tree, &io);
1300         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1301
1302         smbcli_close(cli->tree, fnum);
1303         fname = BASEDIR "\\test4.txt";
1304         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1305         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1306                        "Failed to reopen %s - %s\n",
1307                        fname, smbcli_errstr(cli->tree)));
1308
1309         io.lockx.level = RAW_LOCK_LOCKX;
1310         io.lockx.in.file.fnum = fnum;
1311         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1312         io.lockx.in.timeout = 0;
1313         io.lockx.in.ulock_cnt = 0;
1314         io.lockx.in.lock_cnt = 1;
1315         lock[0].pid = cli->session->pid;
1316         lock[0].offset = 100;
1317         lock[0].count = 10;
1318         io.lockx.in.locks = &lock[0];
1319         status = smb_raw_lock(cli->tree, &io);
1320         CHECK_STATUS(status, NT_STATUS_OK);
1321
1322         start = time(NULL);
1323         io.lockx.in.timeout = t;
1324         req = smb_raw_lock_send(cli->tree, &io);
1325         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1326                        "Failed to setup timed lock (%s)\n", __location__));
1327
1328         io.lockx.in.timeout = 0;
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_FILE_LOCK_CONFLICT);
1346
1347 done:
1348         smb_raw_exit(cli->session);
1349         smbcli_deltree(cli->tree, BASEDIR);
1350         return ret;
1351 }
1352
1353
1354 /*
1355   test LOCKING_ANDX_CHANGE_LOCKTYPE
1356 */
1357 static bool test_changetype(struct torture_context *tctx, 
1358                                                         struct smbcli_state *cli)
1359 {
1360         union smb_lock io;
1361         struct smb_lock_entry lock[2];
1362         NTSTATUS status;
1363         bool ret = true;
1364         int fnum;
1365         uint8_t c = 0;
1366         const char *fname = BASEDIR "\\test.txt";
1367
1368         if (!torture_setup_dir(cli, BASEDIR)) {
1369                 return false;
1370         }
1371
1372         torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1373         io.generic.level = RAW_LOCK_LOCKX;
1374         
1375         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1376         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1377                        "Failed to create %s - %s\n",
1378                        fname, smbcli_errstr(cli->tree)));
1379
1380         io.lockx.level = RAW_LOCK_LOCKX;
1381         io.lockx.in.file.fnum = fnum;
1382         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1383         io.lockx.in.timeout = 0;
1384         io.lockx.in.ulock_cnt = 0;
1385         io.lockx.in.lock_cnt = 1;
1386         lock[0].pid = cli->session->pid;
1387         lock[0].offset = 100;
1388         lock[0].count = 10;
1389         io.lockx.in.locks = &lock[0];
1390         status = smb_raw_lock(cli->tree, &io);
1391         CHECK_STATUS(status, NT_STATUS_OK);
1392
1393         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1394                 torture_result(tctx, TORTURE_FAIL,
1395                         "allowed write on read locked region (%s)\n", __location__);
1396                 ret = false;
1397                 goto done;
1398         }
1399
1400         /* windows server don't seem to support this */
1401         io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1402         status = smb_raw_lock(cli->tree, &io);
1403         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1404
1405         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1406                 torture_result(tctx, TORTURE_FAIL,
1407                         "allowed write after lock change (%s)\n", __location__);
1408                 ret = false;
1409                 goto done;
1410         }
1411
1412 done:
1413         smbcli_close(cli->tree, fnum);
1414         smb_raw_exit(cli->session);
1415         smbcli_deltree(cli->tree, BASEDIR);
1416         return ret;
1417 }
1418
1419 struct double_lock_test {
1420         struct smb_lock_entry lock1;
1421         struct smb_lock_entry lock2;
1422         NTSTATUS exp_status;
1423 };
1424
1425 /**
1426  * Tests zero byte locks.
1427  */
1428 static struct double_lock_test zero_byte_tests[] = {
1429         /* {pid, offset, count}, {pid, offset, count}, status */
1430
1431         /** First, takes a zero byte lock at offset 10. Then:
1432         *   - Taking 0 byte lock at 10 should succeed.
1433         *   - Taking 1 byte locks at 9,10,11 should succeed.
1434         *   - Taking 2 byte lock at 9 should fail.
1435         *   - Taking 2 byte lock at 10 should succeed.
1436         *   - Taking 3 byte lock at 9 should fail.
1437         */
1438         {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1439         {{1000, 10, 0}, {1001, 9, 1},  NT_STATUS_OK},
1440         {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1441         {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1442         {{1000, 10, 0}, {1001, 9, 2},  NT_STATUS_LOCK_NOT_GRANTED},
1443         {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1444         {{1000, 10, 0}, {1001, 9, 3},  NT_STATUS_LOCK_NOT_GRANTED},
1445
1446         /** Same, but opposite order. */
1447         {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1448         {{1001, 9, 1},  {1000, 10, 0}, NT_STATUS_OK},
1449         {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1450         {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1451         {{1001, 9, 2},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1452         {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1453         {{1001, 9, 3},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1454
1455         /** Zero zero case. */
1456         {{1000, 0, 0},  {1001, 0, 0},  NT_STATUS_OK},
1457 };
1458
1459 static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1460 {
1461         union smb_lock io;
1462         NTSTATUS status;
1463         bool ret = true;
1464         int fnum, i;
1465         const char *fname = BASEDIR "\\zero.txt";
1466
1467         torture_comment(tctx, "Testing zero length byte range locks:\n");
1468
1469         if (!torture_setup_dir(cli, BASEDIR)) {
1470                 return false;
1471         }
1472
1473         io.generic.level = RAW_LOCK_LOCKX;
1474
1475         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1476         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1477                        "Failed to create %s - %s\n",
1478                        fname, smbcli_errstr(cli->tree)));
1479
1480         /* Setup initial parameters */
1481         io.lockx.level = RAW_LOCK_LOCKX;
1482         io.lockx.in.file.fnum = fnum;
1483         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1484         io.lockx.in.timeout = 0;
1485
1486         /* Try every combination of locks in zero_byte_tests. The first lock is
1487          * assumed to succeed. The second lock may contend, depending on the
1488          * expected status. */
1489         for (i = 0;
1490              i < ARRAY_SIZE(zero_byte_tests);
1491              i++) {
1492                 torture_comment(tctx, "  ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1493                     zero_byte_tests[i].lock1.pid,
1494                     zero_byte_tests[i].lock1.offset,
1495                     zero_byte_tests[i].lock1.count,
1496                     zero_byte_tests[i].lock2.pid,
1497                     zero_byte_tests[i].lock2.offset,
1498                     zero_byte_tests[i].lock2.count,
1499                     nt_errstr(zero_byte_tests[i].exp_status));
1500
1501                 /* Lock both locks. */
1502                 io.lockx.in.ulock_cnt = 0;
1503                 io.lockx.in.lock_cnt = 1;
1504
1505                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1506                                                     &zero_byte_tests[i].lock1);
1507                 status = smb_raw_lock(cli->tree, &io);
1508                 CHECK_STATUS(status, NT_STATUS_OK);
1509
1510                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1511                                                     &zero_byte_tests[i].lock2);
1512                 status = smb_raw_lock(cli->tree, &io);
1513
1514                 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1515                         NT_STATUS_LOCK_NOT_GRANTED)) {
1516                         /* Allow either of the failure messages and keep going
1517                          * if we see the wrong status. */
1518                         CHECK_STATUS_OR_CONT(status,
1519                             NT_STATUS_LOCK_NOT_GRANTED,
1520                             NT_STATUS_FILE_LOCK_CONFLICT);
1521
1522                 } else {
1523                         CHECK_STATUS_CONT(status,
1524                             zero_byte_tests[i].exp_status);
1525                 }
1526
1527                 /* Unlock both locks. */
1528                 io.lockx.in.ulock_cnt = 1;
1529                 io.lockx.in.lock_cnt = 0;
1530
1531                 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1532                         status = smb_raw_lock(cli->tree, &io);
1533                         CHECK_STATUS(status, NT_STATUS_OK);
1534                 }
1535
1536                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1537                                                     &zero_byte_tests[i].lock1);
1538                 status = smb_raw_lock(cli->tree, &io);
1539                 CHECK_STATUS(status, NT_STATUS_OK);
1540         }
1541
1542 done:
1543         smbcli_close(cli->tree, fnum);
1544         smb_raw_exit(cli->session);
1545         smbcli_deltree(cli->tree, BASEDIR);
1546         return ret;
1547 }
1548
1549 static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1550 {
1551         union smb_lock io;
1552         NTSTATUS status;
1553         bool ret = true;
1554         int fnum1, fnum2;
1555         const char *fname = BASEDIR "\\unlock.txt";
1556         struct smb_lock_entry lock1;
1557         struct smb_lock_entry lock2;
1558
1559         torture_comment(tctx, "Testing LOCKX unlock:\n");
1560
1561         if (!torture_setup_dir(cli, BASEDIR)) {
1562                 return false;
1563         }
1564
1565         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1566         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1567                        "Failed to create %s - %s\n",
1568                        fname, smbcli_errstr(cli->tree)));
1569
1570         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1571         torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1572                        "Failed to create %s - %s\n",
1573                        fname, smbcli_errstr(cli->tree)));
1574
1575         /* Setup initial parameters */
1576         io.lockx.level = RAW_LOCK_LOCKX;
1577         io.lockx.in.timeout = 0;
1578
1579         lock1.pid = cli->session->pid;
1580         lock1.offset = 0;
1581         lock1.count = 10;
1582         lock2.pid = cli->session->pid - 1;
1583         lock2.offset = 0;
1584         lock2.count = 10;
1585
1586         /**
1587          * Take exclusive lock, then unlock it with a shared-unlock call.
1588          */
1589         torture_comment(tctx, "  taking exclusive lock.\n");
1590         io.lockx.in.ulock_cnt = 0;
1591         io.lockx.in.lock_cnt = 1;
1592         io.lockx.in.mode = 0;
1593         io.lockx.in.file.fnum = fnum1;
1594         io.lockx.in.locks = &lock1;
1595         status = smb_raw_lock(cli->tree, &io);
1596         CHECK_STATUS(status, NT_STATUS_OK);
1597
1598         torture_comment(tctx, "  unlock the exclusive with a shared unlock call.\n");
1599         io.lockx.in.ulock_cnt = 1;
1600         io.lockx.in.lock_cnt = 0;
1601         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1602         io.lockx.in.file.fnum = fnum1;
1603         io.lockx.in.locks = &lock1;
1604         status = smb_raw_lock(cli->tree, &io);
1605         CHECK_STATUS(status, NT_STATUS_OK);
1606
1607         torture_comment(tctx, "  try shared lock on pid2/fnum2, testing the unlock.\n");
1608         io.lockx.in.ulock_cnt = 0;
1609         io.lockx.in.lock_cnt = 1;
1610         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1611         io.lockx.in.file.fnum = fnum2;
1612         io.lockx.in.locks = &lock2;
1613         status = smb_raw_lock(cli->tree, &io);
1614         CHECK_STATUS(status, NT_STATUS_OK);
1615
1616         /**
1617          * Unlock a shared lock with an exclusive-unlock call.
1618          */
1619         torture_comment(tctx, "  unlock new shared lock with exclusive unlock call.\n");
1620         io.lockx.in.ulock_cnt = 1;
1621         io.lockx.in.lock_cnt = 0;
1622         io.lockx.in.mode = 0;
1623         io.lockx.in.file.fnum = fnum2;
1624         io.lockx.in.locks = &lock2;
1625         status = smb_raw_lock(cli->tree, &io);
1626         CHECK_STATUS(status, NT_STATUS_OK);
1627
1628         torture_comment(tctx, "  try exclusive lock on pid1, testing the unlock.\n");
1629         io.lockx.in.ulock_cnt = 0;
1630         io.lockx.in.lock_cnt = 1;
1631         io.lockx.in.mode = 0;
1632         io.lockx.in.file.fnum = fnum1;
1633         io.lockx.in.locks = &lock1;
1634         status = smb_raw_lock(cli->tree, &io);
1635         CHECK_STATUS(status, NT_STATUS_OK);
1636
1637         /* cleanup */
1638         io.lockx.in.ulock_cnt = 1;
1639         io.lockx.in.lock_cnt = 0;
1640         status = smb_raw_lock(cli->tree, &io);
1641         CHECK_STATUS(status, NT_STATUS_OK);
1642
1643         /**
1644          * Test unlocking of 0-byte locks.
1645          */
1646
1647         torture_comment(tctx, "  lock shared and exclusive 0-byte locks, testing that Windows "
1648             "always unlocks the exclusive first.\n");
1649         lock1.pid = cli->session->pid;
1650         lock1.offset = 10;
1651         lock1.count = 0;
1652         lock2.pid = cli->session->pid;
1653         lock2.offset = 5;
1654         lock2.count = 10;
1655         io.lockx.in.ulock_cnt = 0;
1656         io.lockx.in.lock_cnt = 1;
1657         io.lockx.in.file.fnum = fnum1;
1658         io.lockx.in.locks = &lock1;
1659
1660         /* lock 0-byte shared
1661          * Note: Order of the shared/exclusive locks doesn't matter. */
1662         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1663         status = smb_raw_lock(cli->tree, &io);
1664         CHECK_STATUS(status, NT_STATUS_OK);
1665
1666         /* lock 0-byte exclusive */
1667         io.lockx.in.mode = 0;
1668         status = smb_raw_lock(cli->tree, &io);
1669         CHECK_STATUS(status, NT_STATUS_OK);
1670
1671         /* test contention */
1672         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1673         io.lockx.in.locks = &lock2;
1674         io.lockx.in.file.fnum = fnum2;
1675         status = smb_raw_lock(cli->tree, &io);
1676         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1677             NT_STATUS_FILE_LOCK_CONFLICT);
1678
1679         /* unlock */
1680         io.lockx.in.ulock_cnt = 1;
1681         io.lockx.in.lock_cnt = 0;
1682         io.lockx.in.file.fnum = fnum1;
1683         io.lockx.in.locks = &lock1;
1684         status = smb_raw_lock(cli->tree, &io);
1685         CHECK_STATUS(status, NT_STATUS_OK);
1686
1687         /* test - can we take a shared lock? */
1688         io.lockx.in.ulock_cnt = 0;
1689         io.lockx.in.lock_cnt = 1;
1690         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1691         io.lockx.in.file.fnum = fnum2;
1692         io.lockx.in.locks = &lock2;
1693         status = smb_raw_lock(cli->tree, &io);
1694
1695         /* XXX Samba 3 will fail this test. This is temporary(because this isn't
1696          * new to Win7, it succeeds in WinXP too), until I can come to a
1697          * resolution as to whether Samba should support this or not. There is
1698          * code to preference unlocking exclusive locks before shared locks,
1699          * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1700         if (TARGET_IS_SAMBA3(tctx)) {
1701                 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1702                     NT_STATUS_FILE_LOCK_CONFLICT);
1703         } else {
1704                 CHECK_STATUS(status, NT_STATUS_OK);
1705         }
1706
1707         /* cleanup */
1708         io.lockx.in.ulock_cnt = 1;
1709         io.lockx.in.lock_cnt = 0;
1710         status = smb_raw_lock(cli->tree, &io);
1711
1712         /* XXX Same as above. */
1713         if (TARGET_IS_SAMBA3(tctx)) {
1714                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1715         } else {
1716                 CHECK_STATUS(status, NT_STATUS_OK);
1717         }
1718
1719         io.lockx.in.file.fnum = fnum1;
1720         io.lockx.in.locks = &lock1;
1721         status = smb_raw_lock(cli->tree, &io);
1722         CHECK_STATUS(status, NT_STATUS_OK);
1723
1724 done:
1725         smbcli_close(cli->tree, fnum1);
1726         smbcli_close(cli->tree, fnum2);
1727         smb_raw_exit(cli->session);
1728         smbcli_deltree(cli->tree, BASEDIR);
1729         return ret;
1730 }
1731
1732 static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1733 {
1734         union smb_lock io;
1735         NTSTATUS status;
1736         bool ret = true;
1737         int fnum1;
1738         const char *fname = BASEDIR "\\unlock_multiple.txt";
1739         struct smb_lock_entry lock1;
1740         struct smb_lock_entry lock2;
1741         struct smb_lock_entry locks[2];
1742
1743         torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1744
1745         if (!torture_setup_dir(cli, BASEDIR)) {
1746                 return false;
1747         }
1748
1749         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1750         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1751                        "Failed to create %s - %s\n",
1752                        fname, smbcli_errstr(cli->tree)));
1753
1754         /* Setup initial parameters */
1755         io.lockx.level = RAW_LOCK_LOCKX;
1756         io.lockx.in.timeout = 0;
1757
1758         lock1.pid = cli->session->pid;
1759         lock1.offset = 0;
1760         lock1.count = 10;
1761         lock2.pid = cli->session->pid;
1762         lock2.offset = 10;
1763         lock2.count = 10;
1764
1765         locks[0] = lock1;
1766         locks[1] = lock2;
1767
1768         io.lockx.in.file.fnum = fnum1;
1769         io.lockx.in.mode = 0; /* exclusive */
1770
1771         /** Test1: Take second lock, but not first. */
1772         torture_comment(tctx, "  unlock 2 locks, first one not locked. Expect no locks "
1773             "unlocked. \n");
1774
1775         io.lockx.in.ulock_cnt = 0;
1776         io.lockx.in.lock_cnt = 1;
1777         io.lockx.in.locks = &lock2;
1778         status = smb_raw_lock(cli->tree, &io);
1779         CHECK_STATUS(status, NT_STATUS_OK);
1780
1781         /* Try to unlock both locks. */
1782         io.lockx.in.ulock_cnt = 2;
1783         io.lockx.in.lock_cnt = 0;
1784         io.lockx.in.locks = locks;
1785
1786         status = smb_raw_lock(cli->tree, &io);
1787         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1788
1789         /* Second lock should not be unlocked. */
1790         io.lockx.in.ulock_cnt = 0;
1791         io.lockx.in.lock_cnt = 1;
1792         io.lockx.in.locks = &lock2;
1793         status = smb_raw_lock(cli->tree, &io);
1794         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1795
1796         /* cleanup */
1797         io.lockx.in.ulock_cnt = 1;
1798         io.lockx.in.lock_cnt = 0;
1799         io.lockx.in.locks = &lock2;
1800         status = smb_raw_lock(cli->tree, &io);
1801         CHECK_STATUS(status, NT_STATUS_OK);
1802
1803         /** Test2: Take first lock, but not second. */
1804         torture_comment(tctx, "  unlock 2 locks, second one not locked. Expect first lock "
1805             "unlocked.\n");
1806
1807         io.lockx.in.ulock_cnt = 0;
1808         io.lockx.in.lock_cnt = 1;
1809         io.lockx.in.locks = &lock1;
1810         status = smb_raw_lock(cli->tree, &io);
1811         CHECK_STATUS(status, NT_STATUS_OK);
1812
1813         /* Try to unlock both locks. */
1814         io.lockx.in.ulock_cnt = 2;
1815         io.lockx.in.lock_cnt = 0;
1816         io.lockx.in.locks = locks;
1817
1818         status = smb_raw_lock(cli->tree, &io);
1819         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1820
1821         /* First lock should be unlocked. */
1822         io.lockx.in.ulock_cnt = 0;
1823         io.lockx.in.lock_cnt = 1;
1824         io.lockx.in.locks = &lock1;
1825         status = smb_raw_lock(cli->tree, &io);
1826         CHECK_STATUS(status, NT_STATUS_OK);
1827
1828         /* cleanup */
1829         io.lockx.in.ulock_cnt = 1;
1830         io.lockx.in.lock_cnt = 0;
1831         io.lockx.in.locks = &lock1;
1832         status = smb_raw_lock(cli->tree, &io);
1833         CHECK_STATUS(status, NT_STATUS_OK);
1834
1835         /* Test3: Request 2 locks, second will contend.  What happens to the
1836          * first? */
1837         torture_comment(tctx, "  request 2 locks, second one will contend. "
1838            "Expect both to fail.\n");
1839
1840         /* Lock the second range */
1841         io.lockx.in.ulock_cnt = 0;
1842         io.lockx.in.lock_cnt = 1;
1843         io.lockx.in.locks = &lock2;
1844         status = smb_raw_lock(cli->tree, &io);
1845         CHECK_STATUS(status, NT_STATUS_OK);
1846
1847         /* Request both locks */
1848         io.lockx.in.ulock_cnt = 0;
1849         io.lockx.in.lock_cnt = 2;
1850         io.lockx.in.locks = locks;
1851
1852         status = smb_raw_lock(cli->tree, &io);
1853         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1854
1855         /* First lock should be unlocked. */
1856         io.lockx.in.ulock_cnt = 0;
1857         io.lockx.in.lock_cnt = 1;
1858         io.lockx.in.locks = &lock1;
1859         status = smb_raw_lock(cli->tree, &io);
1860         CHECK_STATUS(status, NT_STATUS_OK);
1861
1862         /* cleanup */
1863         io.lockx.in.ulock_cnt = 2;
1864         io.lockx.in.lock_cnt = 0;
1865         io.lockx.in.locks = locks;
1866         status = smb_raw_lock(cli->tree, &io);
1867         CHECK_STATUS(status, NT_STATUS_OK);
1868
1869         /* Test4: Request unlock and lock. The lock contends, is the unlock
1870          * then re-locked? */
1871         torture_comment(tctx, "  request unlock and lock, second one will "
1872            "contend. Expect the unlock to succeed.\n");
1873
1874         /* Lock both ranges */
1875         io.lockx.in.ulock_cnt = 0;
1876         io.lockx.in.lock_cnt = 2;
1877         io.lockx.in.locks = locks;
1878         status = smb_raw_lock(cli->tree, &io);
1879         CHECK_STATUS(status, NT_STATUS_OK);
1880
1881         /* Attempt to unlock the first range and lock the second */
1882         io.lockx.in.ulock_cnt = 1;
1883         io.lockx.in.lock_cnt = 1;
1884         io.lockx.in.locks = locks;
1885         status = smb_raw_lock(cli->tree, &io);
1886         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1887
1888         /* The first lock should've been unlocked */
1889         io.lockx.in.ulock_cnt = 0;
1890         io.lockx.in.lock_cnt = 1;
1891         io.lockx.in.locks = &lock1;
1892         status = smb_raw_lock(cli->tree, &io);
1893         CHECK_STATUS(status, NT_STATUS_OK);
1894
1895         /* cleanup */
1896         io.lockx.in.ulock_cnt = 2;
1897         io.lockx.in.lock_cnt = 0;
1898         io.lockx.in.locks = locks;
1899         status = smb_raw_lock(cli->tree, &io);
1900         CHECK_STATUS(status, NT_STATUS_OK);
1901
1902 done:
1903         smbcli_close(cli->tree, fnum1);
1904         smb_raw_exit(cli->session);
1905         smbcli_deltree(cli->tree, BASEDIR);
1906         return ret;
1907 }
1908
1909 /**
1910  * torture_locktest5 covers stacking pretty well, but its missing two tests:
1911  * - stacking an exclusive on top of shared fails
1912  * - stacking two exclusives fail
1913  */
1914 static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
1915 {
1916         union smb_lock io;
1917         NTSTATUS status;
1918         bool ret = true;
1919         int fnum1;
1920         const char *fname = BASEDIR "\\stacking.txt";
1921         struct smb_lock_entry lock1;
1922         struct smb_lock_entry lock2;
1923
1924         torture_comment(tctx, "Testing stacking:\n");
1925
1926         if (!torture_setup_dir(cli, BASEDIR)) {
1927                 return false;
1928         }
1929
1930         io.generic.level = RAW_LOCK_LOCKX;
1931
1932         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1933         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1934                        "Failed to create %s - %s\n",
1935                        fname, smbcli_errstr(cli->tree)));
1936
1937         /* Setup initial parameters */
1938         io.lockx.level = RAW_LOCK_LOCKX;
1939         io.lockx.in.timeout = 0;
1940
1941         lock1.pid = cli->session->pid;
1942         lock1.offset = 0;
1943         lock1.count = 10;
1944         lock2.pid = cli->session->pid - 1;
1945         lock2.offset = 0;
1946         lock2.count = 10;
1947
1948         /**
1949          * Try to take a shared lock, then stack an exclusive.
1950          */
1951         torture_comment(tctx, "  stacking an exclusive on top of a shared lock fails.\n");
1952         io.lockx.in.file.fnum = fnum1;
1953         io.lockx.in.locks = &lock1;
1954
1955         io.lockx.in.ulock_cnt = 0;
1956         io.lockx.in.lock_cnt = 1;
1957         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1958         status = smb_raw_lock(cli->tree, &io);
1959         CHECK_STATUS(status, NT_STATUS_OK);
1960
1961         io.lockx.in.ulock_cnt = 0;
1962         io.lockx.in.lock_cnt = 1;
1963         io.lockx.in.mode = 0;
1964         status = smb_raw_lock(cli->tree, &io);
1965         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1966             NT_STATUS_FILE_LOCK_CONFLICT);
1967
1968         /* cleanup */
1969         io.lockx.in.ulock_cnt = 1;
1970         io.lockx.in.lock_cnt = 0;
1971         status = smb_raw_lock(cli->tree, &io);
1972         CHECK_STATUS(status, NT_STATUS_OK);
1973
1974         /**
1975          * Prove that two exclusive locks do not stack.
1976          */
1977         torture_comment(tctx, "  two exclusive locks do not stack.\n");
1978         io.lockx.in.ulock_cnt = 0;
1979         io.lockx.in.lock_cnt = 1;
1980         io.lockx.in.mode = 0;
1981         status = smb_raw_lock(cli->tree, &io);
1982         CHECK_STATUS(status, NT_STATUS_OK);
1983         status = smb_raw_lock(cli->tree, &io);
1984         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1985             NT_STATUS_FILE_LOCK_CONFLICT);
1986
1987         /* cleanup */
1988         io.lockx.in.ulock_cnt = 1;
1989         io.lockx.in.lock_cnt = 0;
1990         status = smb_raw_lock(cli->tree, &io);
1991         CHECK_STATUS(status, NT_STATUS_OK);
1992
1993 done:
1994         smbcli_close(cli->tree, fnum1);
1995         smb_raw_exit(cli->session);
1996         smbcli_deltree(cli->tree, BASEDIR);
1997         return ret;
1998 }
1999
2000 /**
2001  * Test how 0-byte read requests contend with byte range locks
2002  */
2003 static bool test_zerobyteread(struct torture_context *tctx,
2004                               struct smbcli_state *cli)
2005 {
2006         union smb_lock io;
2007         union smb_read rd;
2008         NTSTATUS status;
2009         bool ret = true;
2010         int fnum1, fnum2;
2011         const char *fname = BASEDIR "\\zerobyteread.txt";
2012         struct smb_lock_entry lock1;
2013         uint8_t c = 1;
2014
2015         if (!torture_setup_dir(cli, BASEDIR)) {
2016                 return false;
2017         }
2018
2019         io.generic.level = RAW_LOCK_LOCKX;
2020
2021         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2022         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2023                        "Failed to create %s - %s\n",
2024                        fname, smbcli_errstr(cli->tree)));
2025
2026         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2027         torture_assert(tctx,(fnum2 != -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
2039         ZERO_STRUCT(rd);
2040         rd.readx.level = RAW_READ_READX;
2041
2042         torture_comment(tctx, "Testing zero byte read on lock range:\n");
2043
2044         /* Take an exclusive lock */
2045         torture_comment(tctx, "  taking exclusive lock.\n");
2046         io.lockx.in.ulock_cnt = 0;
2047         io.lockx.in.lock_cnt = 1;
2048         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2049         io.lockx.in.file.fnum = fnum1;
2050         io.lockx.in.locks = &lock1;
2051         status = smb_raw_lock(cli->tree, &io);
2052         CHECK_STATUS(status, NT_STATUS_OK);
2053
2054         /* Try a zero byte read */
2055         torture_comment(tctx, "  reading 0 bytes.\n");
2056         rd.readx.in.file.fnum = fnum2;
2057         rd.readx.in.offset    = 5;
2058         rd.readx.in.mincnt    = 0;
2059         rd.readx.in.maxcnt    = 0;
2060         rd.readx.in.remaining = 0;
2061         rd.readx.in.read_for_execute = false;
2062         rd.readx.out.data     = &c;
2063         status = smb_raw_read(cli->tree, &rd);
2064         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2065                                       "zero byte read did not return 0 bytes");
2066         CHECK_STATUS(status, NT_STATUS_OK);
2067
2068         /* Unlock lock */
2069         io.lockx.in.ulock_cnt = 1;
2070         io.lockx.in.lock_cnt = 0;
2071         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2072         io.lockx.in.file.fnum = fnum1;
2073         io.lockx.in.locks = &lock1;
2074         status = smb_raw_lock(cli->tree, &io);
2075         CHECK_STATUS(status, NT_STATUS_OK);
2076
2077         torture_comment(tctx, "Testing zero byte read on zero byte lock "
2078                               "range:\n");
2079
2080         /* Take an exclusive lock */
2081         torture_comment(tctx, "  taking exclusive 0-byte lock.\n");
2082         io.lockx.in.ulock_cnt = 0;
2083         io.lockx.in.lock_cnt = 1;
2084         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2085         io.lockx.in.file.fnum = fnum1;
2086         io.lockx.in.locks = &lock1;
2087         lock1.offset = 5;
2088         lock1.count = 0;
2089         status = smb_raw_lock(cli->tree, &io);
2090         CHECK_STATUS(status, NT_STATUS_OK);
2091
2092         /* Try a zero byte read before the lock */
2093         torture_comment(tctx, "  reading 0 bytes before the lock.\n");
2094         rd.readx.in.file.fnum = fnum2;
2095         rd.readx.in.offset    = 4;
2096         rd.readx.in.mincnt    = 0;
2097         rd.readx.in.maxcnt    = 0;
2098         rd.readx.in.remaining = 0;
2099         rd.readx.in.read_for_execute = false;
2100         rd.readx.out.data     = &c;
2101         status = smb_raw_read(cli->tree, &rd);
2102         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2103                                       "zero byte read did not return 0 bytes");
2104         CHECK_STATUS(status, NT_STATUS_OK);
2105
2106         /* Try a zero byte read on the lock */
2107         torture_comment(tctx, "  reading 0 bytes on the lock.\n");
2108         rd.readx.in.file.fnum = fnum2;
2109         rd.readx.in.offset    = 5;
2110         rd.readx.in.mincnt    = 0;
2111         rd.readx.in.maxcnt    = 0;
2112         rd.readx.in.remaining = 0;
2113         rd.readx.in.read_for_execute = false;
2114         rd.readx.out.data     = &c;
2115         status = smb_raw_read(cli->tree, &rd);
2116         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2117                                       "zero byte read did not return 0 bytes");
2118         CHECK_STATUS(status, NT_STATUS_OK);
2119
2120         /* Try a zero byte read after the lock */
2121         torture_comment(tctx, "  reading 0 bytes after the lock.\n");
2122         rd.readx.in.file.fnum = fnum2;
2123         rd.readx.in.offset    = 6;
2124         rd.readx.in.mincnt    = 0;
2125         rd.readx.in.maxcnt    = 0;
2126         rd.readx.in.remaining = 0;
2127         rd.readx.in.read_for_execute = false;
2128         rd.readx.out.data     = &c;
2129         status = smb_raw_read(cli->tree, &rd);
2130         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2131                                       "zero byte read did not return 0 bytes");
2132         CHECK_STATUS(status, NT_STATUS_OK);
2133
2134         /* Unlock lock */
2135         io.lockx.in.ulock_cnt = 1;
2136         io.lockx.in.lock_cnt = 0;
2137         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2138         io.lockx.in.file.fnum = fnum1;
2139         io.lockx.in.locks = &lock1;
2140         status = smb_raw_lock(cli->tree, &io);
2141         CHECK_STATUS(status, NT_STATUS_OK);
2142
2143 done:
2144         smbcli_close(cli->tree, fnum1);
2145         smbcli_close(cli->tree, fnum2);
2146         smb_raw_exit(cli->session);
2147         smbcli_deltree(cli->tree, BASEDIR);
2148         return ret;
2149 }
2150
2151 /*
2152    basic testing of lock calls
2153 */
2154 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
2155 {
2156         struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
2157
2158         torture_suite_add_1smb_test(suite, "lockx", test_lockx);
2159         torture_suite_add_1smb_test(suite, "lock", test_lock);
2160         torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
2161         torture_suite_add_1smb_test(suite, "async", test_async);
2162         torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
2163         torture_suite_add_1smb_test(suite, "changetype", test_changetype);
2164
2165         torture_suite_add_1smb_test(suite, "stacking", test_stacking);
2166         torture_suite_add_1smb_test(suite, "unlock", test_unlock);
2167         torture_suite_add_1smb_test(suite, "multiple_unlock",
2168             test_multiple_unlock);
2169         torture_suite_add_1smb_test(suite, "zerobytelocks",
2170             test_zerobytelocks);
2171         torture_suite_add_1smb_test(suite, "zerobyteread",
2172             test_zerobyteread);
2173
2174         return suite;
2175 }