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