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