/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- test_lock
- test_lockx
- test_pidhigh
- test_async
- test_errorcode
- test_changetype
- test_zerobytelocks
- test_unlock
- test_multiple_unlock
- test_stacking
- torture_raw_lock
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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 }