Make smbtorture4 match Windows behavior.
[Samba/fernandojvsilva.git] / source4 / torture / raw / lock.c
blob6871ed354698db19d2ad0046e03430df55d54308
1 /*
2 Unix SMB/CIFS implementation.
3 test suite for various lock operations
4 Copyright (C) Andrew Tridgell 2003
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.
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.
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/>.
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"
33 #define CHECK_STATUS(status, correct) do { \
34 if (!NT_STATUS_EQUAL(status, correct)) { \
35 torture_result(tctx, TORTURE_FAIL, \
36 "(%s) Incorrect status %s - should be %s\n", \
37 __location__, nt_errstr(status), nt_errstr(correct)); \
38 ret = false; \
39 goto done; \
40 }} while (0)
42 #define CHECK_STATUS_CONT(status, correct) do { \
43 if (!NT_STATUS_EQUAL(status, correct)) { \
44 torture_result(tctx, TORTURE_FAIL, \
45 "(%s) Incorrect status %s - should be %s\n", \
46 __location__, nt_errstr(status), nt_errstr(correct)); \
47 ret = false; \
48 }} while (0)
50 #define CHECK_STATUS_OR(status, correct1, correct2) do { \
51 if ((!NT_STATUS_EQUAL(status, correct1)) && \
52 (!NT_STATUS_EQUAL(status, correct2))) { \
53 torture_result(tctx, TORTURE_FAIL, \
54 "(%s) Incorrect status %s - should be %s or %s\n", \
55 __location__, nt_errstr(status), nt_errstr(correct1), \
56 nt_errstr(correct2)); \
57 ret = false; \
58 goto done; \
59 }} while (0)
61 #define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \
62 if ((!NT_STATUS_EQUAL(status, correct1)) && \
63 (!NT_STATUS_EQUAL(status, correct2))) { \
64 torture_result(tctx, TORTURE_FAIL, \
65 "(%s) Incorrect status %s - should be %s or %s\n", \
66 __location__, nt_errstr(status), nt_errstr(correct1), \
67 nt_errstr(correct2)); \
68 ret = false; \
69 }} while (0)
70 #define BASEDIR "\\testlock"
72 #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
73 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
74 #define TARGET_IS_WINDOWS(_tctx) ((torture_setting_bool(_tctx, "w2k8", false)) || \
75 (torture_setting_bool(_tctx, "win7", false)) || \
76 (torture_setting_bool(_tctx, "w2k3", false)))
77 #define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
78 #define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false))
80 #define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
81 (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
82 #define TARGET_SUPPORTS_SMBLOCK(_tctx) \
83 (torture_setting_bool(_tctx, "smblock_pdu_support", true))
84 #define TARGET_SUPPORTS_OPENX_DENY_DOS(_tctx) \
85 (torture_setting_bool(_tctx, "openx_deny_dos_support", true))
87 test SMBlock and SMBunlock ops
89 static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
91 union smb_lock io;
92 NTSTATUS status;
93 bool ret = true;
94 int fnum;
95 const char *fname = BASEDIR "\\test.txt";
97 if (!TARGET_SUPPORTS_SMBLOCK(tctx))
98 torture_skip(tctx, "Target does not support the SMBlock PDU");
100 if (!torture_setup_dir(cli, BASEDIR)) {
101 return false;
104 torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
105 io.generic.level = RAW_LOCK_LOCK;
107 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
108 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
109 "Failed to create %s - %s\n",
110 fname, smbcli_errstr(cli->tree)));
112 torture_comment(tctx, "Trying 0/0 lock\n");
113 io.lock.level = RAW_LOCK_LOCK;
114 io.lock.in.file.fnum = fnum;
115 io.lock.in.count = 0;
116 io.lock.in.offset = 0;
117 status = smb_raw_lock(cli->tree, &io);
118 CHECK_STATUS(status, NT_STATUS_OK);
119 cli->session->pid++;
120 status = smb_raw_lock(cli->tree, &io);
121 CHECK_STATUS(status, NT_STATUS_OK);
122 cli->session->pid--;
123 io.lock.level = RAW_LOCK_UNLOCK;
124 status = smb_raw_lock(cli->tree, &io);
125 CHECK_STATUS(status, NT_STATUS_OK);
127 torture_comment(tctx, "Trying 0/1 lock\n");
128 io.lock.level = RAW_LOCK_LOCK;
129 io.lock.in.file.fnum = fnum;
130 io.lock.in.count = 1;
131 io.lock.in.offset = 0;
132 status = smb_raw_lock(cli->tree, &io);
133 CHECK_STATUS(status, NT_STATUS_OK);
134 cli->session->pid++;
135 status = smb_raw_lock(cli->tree, &io);
136 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
137 cli->session->pid--;
138 io.lock.level = RAW_LOCK_UNLOCK;
139 status = smb_raw_lock(cli->tree, &io);
140 CHECK_STATUS(status, NT_STATUS_OK);
141 io.lock.level = RAW_LOCK_UNLOCK;
142 status = smb_raw_lock(cli->tree, &io);
143 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
145 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
146 io.lock.level = RAW_LOCK_LOCK;
147 io.lock.in.file.fnum = fnum;
148 io.lock.in.count = 4000;
149 io.lock.in.offset = 0xEEFFFFFF;
150 status = smb_raw_lock(cli->tree, &io);
151 CHECK_STATUS(status, NT_STATUS_OK);
152 cli->session->pid++;
153 status = smb_raw_lock(cli->tree, &io);
154 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
155 cli->session->pid--;
156 io.lock.level = RAW_LOCK_UNLOCK;
157 status = smb_raw_lock(cli->tree, &io);
158 CHECK_STATUS(status, NT_STATUS_OK);
159 io.lock.level = RAW_LOCK_UNLOCK;
160 status = smb_raw_lock(cli->tree, &io);
161 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
163 torture_comment(tctx, "Trying 0xEF000000 lock\n");
164 io.lock.level = RAW_LOCK_LOCK;
165 io.lock.in.file.fnum = fnum;
166 io.lock.in.count = 4000;
167 io.lock.in.offset = 0xEEFFFFFF;
168 status = smb_raw_lock(cli->tree, &io);
169 CHECK_STATUS(status, NT_STATUS_OK);
170 cli->session->pid++;
171 status = smb_raw_lock(cli->tree, &io);
172 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
173 cli->session->pid--;
174 io.lock.level = RAW_LOCK_UNLOCK;
175 status = smb_raw_lock(cli->tree, &io);
176 CHECK_STATUS(status, NT_STATUS_OK);
177 io.lock.level = RAW_LOCK_UNLOCK;
178 status = smb_raw_lock(cli->tree, &io);
179 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
181 torture_comment(tctx, "Trying max lock\n");
182 io.lock.level = RAW_LOCK_LOCK;
183 io.lock.in.file.fnum = fnum;
184 io.lock.in.count = 4000;
185 io.lock.in.offset = 0xEF000000;
186 status = smb_raw_lock(cli->tree, &io);
187 CHECK_STATUS(status, NT_STATUS_OK);
188 cli->session->pid++;
189 status = smb_raw_lock(cli->tree, &io);
190 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
191 cli->session->pid--;
192 io.lock.level = RAW_LOCK_UNLOCK;
193 status = smb_raw_lock(cli->tree, &io);
194 CHECK_STATUS(status, NT_STATUS_OK);
195 io.lock.level = RAW_LOCK_UNLOCK;
196 status = smb_raw_lock(cli->tree, &io);
197 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
199 torture_comment(tctx, "Trying wrong pid unlock\n");
200 io.lock.level = RAW_LOCK_LOCK;
201 io.lock.in.file.fnum = fnum;
202 io.lock.in.count = 4002;
203 io.lock.in.offset = 10001;
204 status = smb_raw_lock(cli->tree, &io);
205 CHECK_STATUS(status, NT_STATUS_OK);
206 cli->session->pid++;
207 io.lock.level = RAW_LOCK_UNLOCK;
208 status = smb_raw_lock(cli->tree, &io);
209 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
210 cli->session->pid--;
211 status = smb_raw_lock(cli->tree, &io);
212 CHECK_STATUS(status, NT_STATUS_OK);
214 done:
215 smbcli_close(cli->tree, fnum);
216 smb_raw_exit(cli->session);
217 smbcli_deltree(cli->tree, BASEDIR);
218 return ret;
223 test locking&X ops
225 static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
227 union smb_lock io;
228 struct smb_lock_entry lock[1];
229 NTSTATUS status;
230 bool ret = true;
231 int fnum;
232 const char *fname = BASEDIR "\\test.txt";
234 if (!torture_setup_dir(cli, BASEDIR)) {
235 return false;
238 torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
239 io.generic.level = RAW_LOCK_LOCKX;
241 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
242 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
243 "Failed to create %s - %s\n",
244 fname, smbcli_errstr(cli->tree)));
246 io.lockx.level = RAW_LOCK_LOCKX;
247 io.lockx.in.file.fnum = fnum;
248 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
249 io.lockx.in.timeout = 0;
250 io.lockx.in.ulock_cnt = 0;
251 io.lockx.in.lock_cnt = 1;
252 lock[0].pid = cli->session->pid;
253 lock[0].offset = 10;
254 lock[0].count = 1;
255 io.lockx.in.locks = &lock[0];
256 status = smb_raw_lock(cli->tree, &io);
257 CHECK_STATUS(status, NT_STATUS_OK);
260 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
261 io.lockx.in.ulock_cnt = 0;
262 io.lockx.in.lock_cnt = 1;
263 lock[0].count = 4000;
264 lock[0].offset = 0xEEFFFFFF;
265 status = smb_raw_lock(cli->tree, &io);
266 CHECK_STATUS(status, NT_STATUS_OK);
267 lock[0].pid++;
268 status = smb_raw_lock(cli->tree, &io);
269 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
270 lock[0].pid--;
271 io.lockx.in.ulock_cnt = 1;
272 io.lockx.in.lock_cnt = 0;
273 status = smb_raw_lock(cli->tree, &io);
274 CHECK_STATUS(status, NT_STATUS_OK);
275 status = smb_raw_lock(cli->tree, &io);
276 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
278 torture_comment(tctx, "Trying 0xEF000000 lock\n");
279 io.lockx.in.ulock_cnt = 0;
280 io.lockx.in.lock_cnt = 1;
281 lock[0].count = 4000;
282 lock[0].offset = 0xEF000000;
283 status = smb_raw_lock(cli->tree, &io);
284 CHECK_STATUS(status, NT_STATUS_OK);
285 lock[0].pid++;
286 status = smb_raw_lock(cli->tree, &io);
287 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
288 lock[0].pid--;
289 io.lockx.in.ulock_cnt = 1;
290 io.lockx.in.lock_cnt = 0;
291 status = smb_raw_lock(cli->tree, &io);
292 CHECK_STATUS(status, NT_STATUS_OK);
293 status = smb_raw_lock(cli->tree, &io);
294 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
296 torture_comment(tctx, "Trying zero lock\n");
297 io.lockx.in.ulock_cnt = 0;
298 io.lockx.in.lock_cnt = 1;
299 lock[0].count = 0;
300 lock[0].offset = ~0;
301 status = smb_raw_lock(cli->tree, &io);
302 CHECK_STATUS(status, NT_STATUS_OK);
303 lock[0].pid++;
304 status = smb_raw_lock(cli->tree, &io);
305 CHECK_STATUS(status, NT_STATUS_OK);
306 lock[0].pid--;
307 io.lockx.in.ulock_cnt = 1;
308 io.lockx.in.lock_cnt = 0;
309 status = smb_raw_lock(cli->tree, &io);
310 CHECK_STATUS(status, NT_STATUS_OK);
311 status = smb_raw_lock(cli->tree, &io);
312 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
314 torture_comment(tctx, "Trying max lock\n");
315 io.lockx.in.ulock_cnt = 0;
316 io.lockx.in.lock_cnt = 1;
317 lock[0].count = 0;
318 lock[0].offset = ~0;
319 status = smb_raw_lock(cli->tree, &io);
320 CHECK_STATUS(status, NT_STATUS_OK);
321 lock[0].pid++;
322 status = smb_raw_lock(cli->tree, &io);
323 CHECK_STATUS(status, NT_STATUS_OK);
324 lock[0].pid--;
325 io.lockx.in.ulock_cnt = 1;
326 io.lockx.in.lock_cnt = 0;
327 status = smb_raw_lock(cli->tree, &io);
328 CHECK_STATUS(status, NT_STATUS_OK);
329 status = smb_raw_lock(cli->tree, &io);
330 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
332 torture_comment(tctx, "Trying 2^63\n");
333 io.lockx.in.ulock_cnt = 0;
334 io.lockx.in.lock_cnt = 1;
335 lock[0].count = 1;
336 lock[0].offset = 1;
337 lock[0].offset <<= 63;
338 status = smb_raw_lock(cli->tree, &io);
339 CHECK_STATUS(status, NT_STATUS_OK);
340 lock[0].pid++;
341 status = smb_raw_lock(cli->tree, &io);
342 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
343 lock[0].pid--;
344 io.lockx.in.ulock_cnt = 1;
345 io.lockx.in.lock_cnt = 0;
346 status = smb_raw_lock(cli->tree, &io);
347 CHECK_STATUS(status, NT_STATUS_OK);
348 status = smb_raw_lock(cli->tree, &io);
349 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
351 torture_comment(tctx, "Trying 2^63 - 1\n");
352 io.lockx.in.ulock_cnt = 0;
353 io.lockx.in.lock_cnt = 1;
354 lock[0].count = 1;
355 lock[0].offset = 1;
356 lock[0].offset <<= 63;
357 lock[0].offset--;
358 status = smb_raw_lock(cli->tree, &io);
359 CHECK_STATUS(status, NT_STATUS_OK);
360 lock[0].pid++;
361 status = smb_raw_lock(cli->tree, &io);
362 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
363 lock[0].pid--;
364 io.lockx.in.ulock_cnt = 1;
365 io.lockx.in.lock_cnt = 0;
366 status = smb_raw_lock(cli->tree, &io);
367 CHECK_STATUS(status, NT_STATUS_OK);
368 status = smb_raw_lock(cli->tree, &io);
369 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
371 torture_comment(tctx, "Trying max lock 2\n");
372 io.lockx.in.ulock_cnt = 0;
373 io.lockx.in.lock_cnt = 1;
374 lock[0].count = 1;
375 lock[0].offset = ~0;
376 status = smb_raw_lock(cli->tree, &io);
377 CHECK_STATUS(status, NT_STATUS_OK);
378 lock[0].pid++;
379 lock[0].count = 2;
380 status = smb_raw_lock(cli->tree, &io);
381 if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(tctx))
382 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
383 else
384 CHECK_STATUS(status, NT_STATUS_OK);
385 lock[0].pid--;
386 io.lockx.in.ulock_cnt = 1;
387 io.lockx.in.lock_cnt = 0;
388 lock[0].count = 1;
389 status = smb_raw_lock(cli->tree, &io);
391 CHECK_STATUS(status, NT_STATUS_OK);
392 status = smb_raw_lock(cli->tree, &io);
393 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
395 done:
396 smbcli_close(cli->tree, fnum);
397 smb_raw_exit(cli->session);
398 smbcli_deltree(cli->tree, BASEDIR);
399 return ret;
403 test high pid
405 static bool test_pidhigh(struct torture_context *tctx,
406 struct smbcli_state *cli)
408 union smb_lock io;
409 struct smb_lock_entry lock[1];
410 NTSTATUS status;
411 bool ret = true;
412 int fnum;
413 const char *fname = BASEDIR "\\test.txt";
414 uint8_t c = 1;
416 if (!torture_setup_dir(cli, BASEDIR)) {
417 return false;
420 torture_comment(tctx, "Testing high pid\n");
421 io.generic.level = RAW_LOCK_LOCKX;
423 cli->session->pid = 1;
425 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
426 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
427 "Failed to create %s - %s\n",
428 fname, smbcli_errstr(cli->tree)));
430 if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
431 torture_result(tctx, TORTURE_FAIL,
432 "Failed to write 1 byte - %s\n",
433 smbcli_errstr(cli->tree));
434 ret = false;
435 goto done;
438 io.lockx.level = RAW_LOCK_LOCKX;
439 io.lockx.in.file.fnum = fnum;
440 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
441 io.lockx.in.timeout = 0;
442 io.lockx.in.ulock_cnt = 0;
443 io.lockx.in.lock_cnt = 1;
444 lock[0].pid = cli->session->pid;
445 lock[0].offset = 0;
446 lock[0].count = 0xFFFFFFFF;
447 io.lockx.in.locks = &lock[0];
448 status = smb_raw_lock(cli->tree, &io);
449 CHECK_STATUS(status, NT_STATUS_OK);
451 if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
452 torture_result(tctx, TORTURE_FAIL,
453 "Failed to read 1 byte - %s\n",
454 smbcli_errstr(cli->tree));
455 ret = false;
456 goto done;
459 cli->session->pid = 2;
461 if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
462 torture_result(tctx, TORTURE_FAIL,
463 "pid is incorrect handled for read with lock!\n");
464 ret = false;
465 goto done;
468 cli->session->pid = 0x10001;
470 if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
471 torture_result(tctx, TORTURE_FAIL,
472 "High pid is used on this server!\n");
473 ret = false;
474 } else {
475 torture_warning(tctx, "High pid is not used on this server (correct)\n");
478 done:
479 smbcli_close(cli->tree, fnum);
480 smb_raw_exit(cli->session);
481 smbcli_deltree(cli->tree, BASEDIR);
482 return ret;
487 test locking&X async operation
489 static bool test_async(struct torture_context *tctx,
490 struct smbcli_state *cli)
492 struct smbcli_session *session;
493 struct smb_composite_sesssetup setup;
494 struct smbcli_tree *tree;
495 union smb_tcon tcon;
496 const char *host, *share;
497 union smb_lock io;
498 struct smb_lock_entry lock[2];
499 NTSTATUS status;
500 bool ret = true;
501 int fnum;
502 const char *fname = BASEDIR "\\test.txt";
503 time_t t;
504 struct smbcli_request *req, *req2;
505 struct smbcli_session_options options;
507 if (!torture_setup_dir(cli, BASEDIR)) {
508 return false;
511 lp_smbcli_session_options(tctx->lp_ctx, &options);
513 torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
514 io.generic.level = RAW_LOCK_LOCKX;
516 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
517 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
518 "Failed to create %s - %s\n",
519 fname, smbcli_errstr(cli->tree)));
521 io.lockx.level = RAW_LOCK_LOCKX;
522 io.lockx.in.file.fnum = fnum;
523 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
524 io.lockx.in.timeout = 0;
525 io.lockx.in.ulock_cnt = 0;
526 io.lockx.in.lock_cnt = 1;
527 lock[0].pid = cli->session->pid;
528 lock[0].offset = 100;
529 lock[0].count = 10;
530 lock[1].pid = cli->session->pid;
531 lock[1].offset = 110;
532 lock[1].count = 10;
533 io.lockx.in.locks = &lock[0];
534 status = smb_raw_lock(cli->tree, &io);
535 CHECK_STATUS(status, NT_STATUS_OK);
537 t = time(NULL);
539 torture_comment(tctx, "testing cancel by CANCEL_LOCK\n");
541 /* setup a timed lock */
542 io.lockx.in.timeout = 10000;
543 req = smb_raw_lock_send(cli->tree, &io);
544 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
545 "Failed to setup timed lock (%s)\n", __location__));
547 /* cancel the wrong range */
548 lock[0].offset = 0;
549 io.lockx.in.timeout = 0;
550 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
551 status = smb_raw_lock(cli->tree, &io);
552 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
554 /* cancel with the wrong bits set */
555 lock[0].offset = 100;
556 io.lockx.in.timeout = 0;
557 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
558 status = smb_raw_lock(cli->tree, &io);
559 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
561 /* cancel the right range */
562 lock[0].offset = 100;
563 io.lockx.in.timeout = 0;
564 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
565 status = smb_raw_lock(cli->tree, &io);
566 CHECK_STATUS(status, NT_STATUS_OK);
568 /* receive the failed lock request */
569 status = smbcli_request_simple_recv(req);
570 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
572 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
573 "lock cancel was not immediate (%s)\n", __location__));
575 /* MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
576 * if the lock vector contains one entry. When given mutliple cancel
577 * requests in a single PDU we expect the server to return an
578 * error. Samba4 handles this correctly. Windows servers seem to
579 * accept the request but only cancel the first lock. Samba3
580 * now does what Windows does (JRA).
582 torture_comment(tctx, "testing multiple cancel\n");
584 /* acquire second lock */
585 io.lockx.in.timeout = 0;
586 io.lockx.in.ulock_cnt = 0;
587 io.lockx.in.lock_cnt = 1;
588 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
589 io.lockx.in.locks = &lock[1];
590 status = smb_raw_lock(cli->tree, &io);
591 CHECK_STATUS(status, NT_STATUS_OK);
593 /* setup 2 timed locks */
594 t = time(NULL);
595 io.lockx.in.timeout = 10000;
596 io.lockx.in.lock_cnt = 1;
597 io.lockx.in.locks = &lock[0];
598 req = smb_raw_lock_send(cli->tree, &io);
599 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
600 "Failed to setup timed lock (%s)\n", __location__));
601 io.lockx.in.locks = &lock[1];
602 req2 = smb_raw_lock_send(cli->tree, &io);
603 torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
604 "Failed to setup timed lock (%s)\n", __location__));
606 /* try to cancel both locks in the same packet */
607 io.lockx.in.timeout = 0;
608 io.lockx.in.lock_cnt = 2;
609 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
610 io.lockx.in.locks = lock;
611 status = smb_raw_lock(cli->tree, &io);
612 CHECK_STATUS(status, NT_STATUS_OK);
614 torture_warning(tctx, "Target server accepted a lock cancel "
615 "request with multiple locks. This violates "
616 "MS-CIFS 2.2.4.32.1.\n");
618 /* receive the failed lock requests */
619 status = smbcli_request_simple_recv(req);
620 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
622 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
623 "first lock was not cancelled immediately (%s)\n",
624 __location__));
626 /* send cancel to second lock */
627 io.lockx.in.timeout = 0;
628 io.lockx.in.lock_cnt = 1;
629 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK |
630 LOCKING_ANDX_LARGE_FILES;
631 io.lockx.in.locks = &lock[1];
632 status = smb_raw_lock(cli->tree, &io);
633 CHECK_STATUS(status, NT_STATUS_OK);
635 status = smbcli_request_simple_recv(req2);
636 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
638 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
639 "second lock was not cancelled immediately (%s)\n",
640 __location__));
642 /* cleanup the second lock */
643 io.lockx.in.ulock_cnt = 1;
644 io.lockx.in.lock_cnt = 0;
645 io.lockx.in.locks = &lock[1];
646 status = smb_raw_lock(cli->tree, &io);
647 CHECK_STATUS(status, NT_STATUS_OK);
649 torture_comment(tctx, "testing cancel by unlock\n");
650 io.lockx.in.ulock_cnt = 0;
651 io.lockx.in.lock_cnt = 1;
652 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
653 io.lockx.in.timeout = 0;
654 io.lockx.in.locks = &lock[0];
655 status = smb_raw_lock(cli->tree, &io);
656 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
658 io.lockx.in.timeout = 5000;
659 req = smb_raw_lock_send(cli->tree, &io);
660 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
661 "Failed to setup timed lock (%s)\n", __location__));
663 io.lockx.in.ulock_cnt = 1;
664 io.lockx.in.lock_cnt = 0;
665 status = smb_raw_lock(cli->tree, &io);
666 CHECK_STATUS(status, NT_STATUS_OK);
668 t = time(NULL);
669 status = smbcli_request_simple_recv(req);
670 CHECK_STATUS(status, NT_STATUS_OK);
672 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
673 "lock cancel by unlock was not immediate (%s) - took %d secs\n",
674 __location__, (int)(time(NULL)-t)));
676 torture_comment(tctx, "testing cancel by close\n");
677 io.lockx.in.ulock_cnt = 0;
678 io.lockx.in.lock_cnt = 1;
679 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
680 io.lockx.in.timeout = 0;
681 status = smb_raw_lock(cli->tree, &io);
682 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
684 t = time(NULL);
685 io.lockx.in.timeout = 10000;
686 req = smb_raw_lock_send(cli->tree, &io);
687 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
688 "Failed to setup timed lock (%s)\n", __location__));
690 status = smbcli_close(cli->tree, fnum);
691 CHECK_STATUS(status, NT_STATUS_OK);
693 status = smbcli_request_simple_recv(req);
694 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
696 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
697 "lock cancel by close was not immediate (%s)\n", __location__));
699 torture_comment(tctx, "create a new sessions\n");
700 session = smbcli_session_init(cli->transport, tctx, false, options);
701 setup.in.sesskey = cli->transport->negotiate.sesskey;
702 setup.in.capabilities = cli->transport->negotiate.capabilities;
703 setup.in.workgroup = lp_workgroup(tctx->lp_ctx);
704 setup.in.credentials = cmdline_credentials;
705 setup.in.gensec_settings = lp_gensec_settings(tctx, tctx->lp_ctx);
706 status = smb_composite_sesssetup(session, &setup);
707 CHECK_STATUS(status, NT_STATUS_OK);
708 session->vuid = setup.out.vuid;
710 torture_comment(tctx, "create new tree context\n");
711 share = torture_setting_string(tctx, "share", NULL);
712 host = torture_setting_string(tctx, "host", NULL);
713 tree = smbcli_tree_init(session, tctx, false);
714 tcon.generic.level = RAW_TCON_TCONX;
715 tcon.tconx.in.flags = 0;
716 tcon.tconx.in.password = data_blob(NULL, 0);
717 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
718 tcon.tconx.in.device = "A:";
719 status = smb_raw_tcon(tree, tctx, &tcon);
720 CHECK_STATUS(status, NT_STATUS_OK);
721 tree->tid = tcon.tconx.out.tid;
723 torture_comment(tctx, "testing cancel by exit\n");
724 fname = BASEDIR "\\test_exit.txt";
725 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
726 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
727 "Failed to reopen %s - %s\n",
728 fname, smbcli_errstr(tree)));
730 io.lockx.level = RAW_LOCK_LOCKX;
731 io.lockx.in.file.fnum = fnum;
732 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
733 io.lockx.in.timeout = 0;
734 io.lockx.in.ulock_cnt = 0;
735 io.lockx.in.lock_cnt = 1;
736 lock[0].pid = session->pid;
737 lock[0].offset = 100;
738 lock[0].count = 10;
739 io.lockx.in.locks = &lock[0];
740 status = smb_raw_lock(tree, &io);
741 CHECK_STATUS(status, NT_STATUS_OK);
743 io.lockx.in.ulock_cnt = 0;
744 io.lockx.in.lock_cnt = 1;
745 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
746 io.lockx.in.timeout = 0;
747 status = smb_raw_lock(tree, &io);
748 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
750 io.lockx.in.timeout = 10000;
751 t = time(NULL);
752 req = smb_raw_lock_send(tree, &io);
753 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
754 "Failed to setup timed lock (%s)\n", __location__));
756 status = smb_raw_exit(session);
757 CHECK_STATUS(status, NT_STATUS_OK);
759 status = smbcli_request_simple_recv(req);
760 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
762 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
763 "lock cancel by exit was not immediate (%s)\n", __location__));
765 torture_comment(tctx, "testing cancel by ulogoff\n");
766 fname = BASEDIR "\\test_ulogoff.txt";
767 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
768 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
769 "Failed to reopen %s - %s\n",
770 fname, smbcli_errstr(tree)));
772 io.lockx.level = RAW_LOCK_LOCKX;
773 io.lockx.in.file.fnum = fnum;
774 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
775 io.lockx.in.timeout = 0;
776 io.lockx.in.ulock_cnt = 0;
777 io.lockx.in.lock_cnt = 1;
778 lock[0].pid = session->pid;
779 lock[0].offset = 100;
780 lock[0].count = 10;
781 io.lockx.in.locks = &lock[0];
782 status = smb_raw_lock(tree, &io);
783 CHECK_STATUS(status, NT_STATUS_OK);
785 io.lockx.in.ulock_cnt = 0;
786 io.lockx.in.lock_cnt = 1;
787 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
788 io.lockx.in.timeout = 0;
789 status = smb_raw_lock(tree, &io);
790 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
792 io.lockx.in.timeout = 10000;
793 t = time(NULL);
794 req = smb_raw_lock_send(tree, &io);
795 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
796 "Failed to setup timed lock (%s)\n", __location__));
798 status = smb_raw_ulogoff(session);
799 CHECK_STATUS(status, NT_STATUS_OK);
801 status = smbcli_request_simple_recv(req);
802 if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
803 torture_result(tctx, TORTURE_FAIL,
804 "lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n",
805 nt_errstr(status));
806 smb_tree_disconnect(tree);
807 smb_raw_exit(session);
808 goto done;
810 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
812 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
813 "lock cancel by ulogoff was not immediate (%s)\n", __location__));
815 torture_comment(tctx, "testing cancel by tdis\n");
816 tree->session = cli->session;
818 fname = BASEDIR "\\test_tdis.txt";
819 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
820 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
821 "Failed to reopen %s - %s\n",
822 fname, smbcli_errstr(tree)));
824 io.lockx.level = RAW_LOCK_LOCKX;
825 io.lockx.in.file.fnum = fnum;
826 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
827 io.lockx.in.timeout = 0;
828 io.lockx.in.ulock_cnt = 0;
829 io.lockx.in.lock_cnt = 1;
830 lock[0].pid = cli->session->pid;
831 lock[0].offset = 100;
832 lock[0].count = 10;
833 io.lockx.in.locks = &lock[0];
834 status = smb_raw_lock(tree, &io);
835 CHECK_STATUS(status, NT_STATUS_OK);
837 status = smb_raw_lock(tree, &io);
838 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
840 io.lockx.in.timeout = 10000;
841 t = time(NULL);
842 req = smb_raw_lock_send(tree, &io);
843 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
844 "Failed to setup timed lock (%s)\n", __location__));
846 status = smb_tree_disconnect(tree);
847 CHECK_STATUS(status, NT_STATUS_OK);
849 status = smbcli_request_simple_recv(req);
850 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
852 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
853 "lock cancel by tdis was not immediate (%s)\n", __location__));
855 done:
856 smb_raw_exit(cli->session);
857 smbcli_deltree(cli->tree, BASEDIR);
858 return ret;
862 test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
864 static bool test_errorcode(struct torture_context *tctx,
865 struct smbcli_state *cli)
867 union smb_lock io;
868 union smb_open op;
869 struct smb_lock_entry lock[2];
870 NTSTATUS status;
871 bool ret = true;
872 int fnum, fnum2;
873 const char *fname;
874 struct smbcli_request *req;
875 time_t start;
876 int t;
877 int delay;
878 uint16_t deny_mode = 0;
880 if (!torture_setup_dir(cli, BASEDIR)) {
881 return false;
884 torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
886 torture_comment(tctx, "testing with timeout = 0\n");
887 fname = BASEDIR "\\test0.txt";
888 t = 0;
891 * the first run is with t = 0,
892 * the second with t > 0 (=1)
894 next_run:
896 * use the DENY_DOS mode, that creates two fnum's of one low-level
897 * file handle, this demonstrates that the cache is per fnum, not
898 * per file handle
900 if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
901 deny_mode = OPENX_MODE_DENY_DOS;
902 else
903 deny_mode = OPENX_MODE_DENY_NONE;
905 op.openx.level = RAW_OPEN_OPENX;
906 op.openx.in.fname = fname;
907 op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
908 op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
909 op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
910 op.openx.in.search_attrs = 0;
911 op.openx.in.file_attrs = 0;
912 op.openx.in.write_time = 0;
913 op.openx.in.size = 0;
914 op.openx.in.timeout = 0;
916 status = smb_raw_open(cli->tree, tctx, &op);
917 CHECK_STATUS(status, NT_STATUS_OK);
918 fnum = op.openx.out.file.fnum;
920 status = smb_raw_open(cli->tree, tctx, &op);
921 CHECK_STATUS(status, NT_STATUS_OK);
922 fnum2 = op.openx.out.file.fnum;
924 io.lockx.level = RAW_LOCK_LOCKX;
925 io.lockx.in.file.fnum = fnum;
926 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
927 io.lockx.in.timeout = t;
928 io.lockx.in.ulock_cnt = 0;
929 io.lockx.in.lock_cnt = 1;
930 lock[0].pid = cli->session->pid;
931 lock[0].offset = 100;
932 lock[0].count = 10;
933 io.lockx.in.locks = &lock[0];
934 status = smb_raw_lock(cli->tree, &io);
935 CHECK_STATUS(status, NT_STATUS_OK);
938 * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
939 * this also demonstrates that the error code cache is per file handle
940 * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
942 io.lockx.in.file.fnum = fnum2;
943 status = smb_raw_lock(cli->tree, &io);
944 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
946 io.lockx.in.file.fnum = fnum;
947 status = smb_raw_lock(cli->tree, &io);
948 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
950 /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
951 io.lockx.in.file.fnum = fnum;
952 status = smb_raw_lock(cli->tree, &io);
953 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
955 io.lockx.in.file.fnum = fnum2;
956 status = smb_raw_lock(cli->tree, &io);
957 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
959 io.lockx.in.file.fnum = fnum;
960 status = smb_raw_lock(cli->tree, &io);
961 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
963 io.lockx.in.file.fnum = fnum2;
964 status = smb_raw_lock(cli->tree, &io);
965 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
967 /* demonstrate that the smbpid doesn't matter */
968 lock[0].pid++;
969 io.lockx.in.file.fnum = fnum;
970 status = smb_raw_lock(cli->tree, &io);
971 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
973 io.lockx.in.file.fnum = fnum2;
974 status = smb_raw_lock(cli->tree, &io);
975 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
976 lock[0].pid--;
979 * demonstrate the a successful lock with count = 0 and the same offset,
980 * doesn't reset the error cache
982 lock[0].offset = 100;
983 lock[0].count = 0;
984 io.lockx.in.file.fnum = fnum;
985 status = smb_raw_lock(cli->tree, &io);
986 CHECK_STATUS(status, NT_STATUS_OK);
988 io.lockx.in.file.fnum = fnum2;
989 status = smb_raw_lock(cli->tree, &io);
990 CHECK_STATUS(status, NT_STATUS_OK);
992 lock[0].offset = 100;
993 lock[0].count = 10;
994 io.lockx.in.file.fnum = fnum;
995 status = smb_raw_lock(cli->tree, &io);
996 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
998 io.lockx.in.file.fnum = fnum2;
999 status = smb_raw_lock(cli->tree, &io);
1000 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1003 * demonstrate the a successful lock with count = 0 and outside the locked range,
1004 * doesn't reset the error cache
1006 lock[0].offset = 110;
1007 lock[0].count = 0;
1008 io.lockx.in.file.fnum = fnum;
1009 status = smb_raw_lock(cli->tree, &io);
1010 CHECK_STATUS(status, NT_STATUS_OK);
1012 io.lockx.in.file.fnum = fnum2;
1013 status = smb_raw_lock(cli->tree, &io);
1014 CHECK_STATUS(status, NT_STATUS_OK);
1016 lock[0].offset = 100;
1017 lock[0].count = 10;
1018 io.lockx.in.file.fnum = fnum;
1019 status = smb_raw_lock(cli->tree, &io);
1020 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1022 io.lockx.in.file.fnum = fnum2;
1023 status = smb_raw_lock(cli->tree, &io);
1024 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1026 lock[0].offset = 99;
1027 lock[0].count = 0;
1028 io.lockx.in.file.fnum = fnum;
1029 status = smb_raw_lock(cli->tree, &io);
1030 CHECK_STATUS(status, NT_STATUS_OK);
1032 io.lockx.in.file.fnum = fnum2;
1033 status = smb_raw_lock(cli->tree, &io);
1034 CHECK_STATUS(status, NT_STATUS_OK);
1036 lock[0].offset = 100;
1037 lock[0].count = 10;
1038 io.lockx.in.file.fnum = fnum;
1039 status = smb_raw_lock(cli->tree, &io);
1040 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1042 io.lockx.in.file.fnum = fnum2;
1043 status = smb_raw_lock(cli->tree, &io);
1044 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1046 /* demonstrate that a changing count doesn't reset the error cache */
1047 lock[0].offset = 100;
1048 lock[0].count = 5;
1049 io.lockx.in.file.fnum = fnum;
1050 status = smb_raw_lock(cli->tree, &io);
1051 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1053 io.lockx.in.file.fnum = fnum2;
1054 status = smb_raw_lock(cli->tree, &io);
1055 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1057 lock[0].offset = 100;
1058 lock[0].count = 15;
1059 io.lockx.in.file.fnum = fnum;
1060 status = smb_raw_lock(cli->tree, &io);
1061 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1063 io.lockx.in.file.fnum = fnum2;
1064 status = smb_raw_lock(cli->tree, &io);
1065 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1068 * demonstrate the a lock with count = 0 and inside the locked range,
1069 * fails and resets the error cache
1071 lock[0].offset = 101;
1072 lock[0].count = 0;
1073 io.lockx.in.file.fnum = fnum;
1074 status = smb_raw_lock(cli->tree, &io);
1075 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1076 status = smb_raw_lock(cli->tree, &io);
1077 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1079 io.lockx.in.file.fnum = fnum2;
1080 status = smb_raw_lock(cli->tree, &io);
1081 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1082 status = smb_raw_lock(cli->tree, &io);
1083 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1085 lock[0].offset = 100;
1086 lock[0].count = 10;
1087 io.lockx.in.file.fnum = fnum;
1088 status = smb_raw_lock(cli->tree, &io);
1089 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1090 status = smb_raw_lock(cli->tree, &io);
1091 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1093 io.lockx.in.file.fnum = fnum2;
1094 status = smb_raw_lock(cli->tree, &io);
1095 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1096 status = smb_raw_lock(cli->tree, &io);
1097 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1099 /* demonstrate the a changing offset, resets the error cache */
1100 lock[0].offset = 105;
1101 lock[0].count = 10;
1102 io.lockx.in.file.fnum = fnum;
1103 status = smb_raw_lock(cli->tree, &io);
1104 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1105 status = smb_raw_lock(cli->tree, &io);
1106 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
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 status = smb_raw_lock(cli->tree, &io);
1112 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1114 lock[0].offset = 100;
1115 lock[0].count = 10;
1116 io.lockx.in.file.fnum = fnum;
1117 status = smb_raw_lock(cli->tree, &io);
1118 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1119 status = smb_raw_lock(cli->tree, &io);
1120 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1122 io.lockx.in.file.fnum = fnum2;
1123 status = smb_raw_lock(cli->tree, &io);
1124 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1125 status = smb_raw_lock(cli->tree, &io);
1126 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1128 lock[0].offset = 95;
1129 lock[0].count = 9;
1130 io.lockx.in.file.fnum = fnum;
1131 status = smb_raw_lock(cli->tree, &io);
1132 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1133 status = smb_raw_lock(cli->tree, &io);
1134 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1136 io.lockx.in.file.fnum = fnum2;
1137 status = smb_raw_lock(cli->tree, &io);
1138 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1139 status = smb_raw_lock(cli->tree, &io);
1140 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1142 lock[0].offset = 100;
1143 lock[0].count = 10;
1144 io.lockx.in.file.fnum = fnum;
1145 status = smb_raw_lock(cli->tree, &io);
1146 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1147 status = smb_raw_lock(cli->tree, &io);
1148 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1150 io.lockx.in.file.fnum = fnum2;
1151 status = smb_raw_lock(cli->tree, &io);
1152 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1153 status = smb_raw_lock(cli->tree, &io);
1154 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1157 * demonstrate the a successful lock in a different range,
1158 * doesn't reset the cache, the failing lock on the 2nd handle
1159 * resets the cache
1161 lock[0].offset = 120;
1162 lock[0].count = 15;
1163 io.lockx.in.file.fnum = fnum;
1164 status = smb_raw_lock(cli->tree, &io);
1165 CHECK_STATUS(status, NT_STATUS_OK);
1167 io.lockx.in.file.fnum = fnum2;
1168 status = smb_raw_lock(cli->tree, &io);
1169 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1171 lock[0].offset = 100;
1172 lock[0].count = 10;
1173 io.lockx.in.file.fnum = fnum;
1174 status = smb_raw_lock(cli->tree, &io);
1175 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1176 status = smb_raw_lock(cli->tree, &io);
1177 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1179 io.lockx.in.file.fnum = fnum2;
1180 status = smb_raw_lock(cli->tree, &io);
1181 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1182 status = smb_raw_lock(cli->tree, &io);
1183 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1185 /* end of the loop */
1186 if (t == 0) {
1187 smb_raw_exit(cli->session);
1188 t = 1;
1189 torture_comment(tctx, "testing with timeout > 0 (=%d)\n",
1191 fname = BASEDIR "\\test1.txt";
1192 goto next_run;
1195 t = 4000;
1196 torture_comment(tctx, "testing special cases with timeout > 0 (=%d)\n",
1200 * the following 3 test sections demonstrate that
1201 * the cache is only set when the error is reported
1202 * to the client (after the timeout went by)
1204 smb_raw_exit(cli->session);
1205 torture_comment(tctx, "testing a conflict while a lock is pending\n");
1206 fname = BASEDIR "\\test2.txt";
1207 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1208 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1209 "Failed to reopen %s - %s\n",
1210 fname, smbcli_errstr(cli->tree)));
1212 io.lockx.level = RAW_LOCK_LOCKX;
1213 io.lockx.in.file.fnum = fnum;
1214 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1215 io.lockx.in.timeout = 0;
1216 io.lockx.in.ulock_cnt = 0;
1217 io.lockx.in.lock_cnt = 1;
1218 lock[0].pid = cli->session->pid;
1219 lock[0].offset = 100;
1220 lock[0].count = 10;
1221 io.lockx.in.locks = &lock[0];
1222 status = smb_raw_lock(cli->tree, &io);
1223 CHECK_STATUS(status, NT_STATUS_OK);
1225 start = time(NULL);
1226 io.lockx.in.timeout = t;
1227 req = smb_raw_lock_send(cli->tree, &io);
1228 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1229 "Failed to setup timed lock (%s)\n", __location__));
1231 io.lockx.in.timeout = 0;
1232 lock[0].offset = 105;
1233 lock[0].count = 10;
1234 status = smb_raw_lock(cli->tree, &io);
1235 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1237 status = smbcli_request_simple_recv(req);
1238 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1240 delay = t / 1000;
1241 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1242 delay /= 2;
1245 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1246 "lock comes back to early timeout[%d] delay[%d]"
1247 "(%s)\n", t, delay, __location__));
1249 status = smb_raw_lock(cli->tree, &io);
1250 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1252 smbcli_close(cli->tree, fnum);
1253 fname = BASEDIR "\\test3.txt";
1254 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1255 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1256 "Failed to reopen %s - %s\n",
1257 fname, smbcli_errstr(cli->tree)));
1259 io.lockx.level = RAW_LOCK_LOCKX;
1260 io.lockx.in.file.fnum = fnum;
1261 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1262 io.lockx.in.timeout = 0;
1263 io.lockx.in.ulock_cnt = 0;
1264 io.lockx.in.lock_cnt = 1;
1265 lock[0].pid = cli->session->pid;
1266 lock[0].offset = 100;
1267 lock[0].count = 10;
1268 io.lockx.in.locks = &lock[0];
1269 status = smb_raw_lock(cli->tree, &io);
1270 CHECK_STATUS(status, NT_STATUS_OK);
1272 start = time(NULL);
1273 io.lockx.in.timeout = t;
1274 req = smb_raw_lock_send(cli->tree, &io);
1275 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1276 "Failed to setup timed lock (%s)\n", __location__));
1278 io.lockx.in.timeout = 0;
1279 lock[0].offset = 105;
1280 lock[0].count = 10;
1281 status = smb_raw_lock(cli->tree, &io);
1282 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1284 status = smbcli_request_simple_recv(req);
1285 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1287 delay = t / 1000;
1288 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1289 delay /= 2;
1292 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1293 "lock comes back to early timeout[%d] delay[%d]"
1294 "(%s)\n", t, delay, __location__));
1296 lock[0].offset = 100;
1297 lock[0].count = 10;
1298 status = smb_raw_lock(cli->tree, &io);
1299 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1301 smbcli_close(cli->tree, fnum);
1302 fname = BASEDIR "\\test4.txt";
1303 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1304 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1305 "Failed to reopen %s - %s\n",
1306 fname, smbcli_errstr(cli->tree)));
1308 io.lockx.level = RAW_LOCK_LOCKX;
1309 io.lockx.in.file.fnum = fnum;
1310 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1311 io.lockx.in.timeout = 0;
1312 io.lockx.in.ulock_cnt = 0;
1313 io.lockx.in.lock_cnt = 1;
1314 lock[0].pid = cli->session->pid;
1315 lock[0].offset = 100;
1316 lock[0].count = 10;
1317 io.lockx.in.locks = &lock[0];
1318 status = smb_raw_lock(cli->tree, &io);
1319 CHECK_STATUS(status, NT_STATUS_OK);
1321 start = time(NULL);
1322 io.lockx.in.timeout = t;
1323 req = smb_raw_lock_send(cli->tree, &io);
1324 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1325 "Failed to setup timed lock (%s)\n", __location__));
1327 io.lockx.in.timeout = 0;
1328 status = smb_raw_lock(cli->tree, &io);
1329 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1331 status = smbcli_request_simple_recv(req);
1332 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1334 delay = t / 1000;
1335 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1336 delay /= 2;
1339 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1340 "lock comes back to early timeout[%d] delay[%d]"
1341 "(%s)\n", t, delay, __location__));
1343 status = smb_raw_lock(cli->tree, &io);
1344 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1346 done:
1347 smb_raw_exit(cli->session);
1348 smbcli_deltree(cli->tree, BASEDIR);
1349 return ret;
1354 test LOCKING_ANDX_CHANGE_LOCKTYPE
1356 static bool test_changetype(struct torture_context *tctx,
1357 struct smbcli_state *cli)
1359 union smb_lock io;
1360 struct smb_lock_entry lock[2];
1361 NTSTATUS status;
1362 bool ret = true;
1363 int fnum;
1364 uint8_t c = 0;
1365 const char *fname = BASEDIR "\\test.txt";
1367 if (!torture_setup_dir(cli, BASEDIR)) {
1368 return false;
1371 torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1372 io.generic.level = RAW_LOCK_LOCKX;
1374 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1375 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1376 "Failed to create %s - %s\n",
1377 fname, smbcli_errstr(cli->tree)));
1379 io.lockx.level = RAW_LOCK_LOCKX;
1380 io.lockx.in.file.fnum = fnum;
1381 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1382 io.lockx.in.timeout = 0;
1383 io.lockx.in.ulock_cnt = 0;
1384 io.lockx.in.lock_cnt = 1;
1385 lock[0].pid = cli->session->pid;
1386 lock[0].offset = 100;
1387 lock[0].count = 10;
1388 io.lockx.in.locks = &lock[0];
1389 status = smb_raw_lock(cli->tree, &io);
1390 CHECK_STATUS(status, NT_STATUS_OK);
1392 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1393 torture_result(tctx, TORTURE_FAIL,
1394 "allowed write on read locked region (%s)\n", __location__);
1395 ret = false;
1396 goto done;
1399 /* windows server don't seem to support this */
1400 io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1401 status = smb_raw_lock(cli->tree, &io);
1402 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1404 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1405 torture_result(tctx, TORTURE_FAIL,
1406 "allowed write after lock change (%s)\n", __location__);
1407 ret = false;
1408 goto done;
1411 done:
1412 smbcli_close(cli->tree, fnum);
1413 smb_raw_exit(cli->session);
1414 smbcli_deltree(cli->tree, BASEDIR);
1415 return ret;
1418 struct double_lock_test {
1419 struct smb_lock_entry lock1;
1420 struct smb_lock_entry lock2;
1421 NTSTATUS exp_status;
1425 * Tests zero byte locks.
1427 static struct double_lock_test zero_byte_tests[] = {
1428 /* {pid, offset, count}, {pid, offset, count}, status */
1430 /** First, takes a zero byte lock at offset 10. Then:
1431 * - Taking 0 byte lock at 10 should succeed.
1432 * - Taking 1 byte locks at 9,10,11 should succeed.
1433 * - Taking 2 byte lock at 9 should fail.
1434 * - Taking 2 byte lock at 10 should succeed.
1435 * - Taking 3 byte lock at 9 should fail.
1437 {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1438 {{1000, 10, 0}, {1001, 9, 1}, NT_STATUS_OK},
1439 {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1440 {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1441 {{1000, 10, 0}, {1001, 9, 2}, NT_STATUS_LOCK_NOT_GRANTED},
1442 {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1443 {{1000, 10, 0}, {1001, 9, 3}, NT_STATUS_LOCK_NOT_GRANTED},
1445 /** Same, but opposite order. */
1446 {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1447 {{1001, 9, 1}, {1000, 10, 0}, NT_STATUS_OK},
1448 {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1449 {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1450 {{1001, 9, 2}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1451 {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1452 {{1001, 9, 3}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1454 /** Zero zero case. */
1455 {{1000, 0, 0}, {1001, 0, 0}, NT_STATUS_OK},
1458 static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1460 union smb_lock io;
1461 NTSTATUS status;
1462 bool ret = true;
1463 int fnum, i;
1464 const char *fname = BASEDIR "\\zero.txt";
1466 torture_comment(tctx, "Testing zero length byte range locks:\n");
1468 if (!torture_setup_dir(cli, BASEDIR)) {
1469 return false;
1472 io.generic.level = RAW_LOCK_LOCKX;
1474 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1475 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1476 "Failed to create %s - %s\n",
1477 fname, smbcli_errstr(cli->tree)));
1479 /* Setup initial parameters */
1480 io.lockx.level = RAW_LOCK_LOCKX;
1481 io.lockx.in.file.fnum = fnum;
1482 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1483 io.lockx.in.timeout = 0;
1485 /* Try every combination of locks in zero_byte_tests. The first lock is
1486 * assumed to succeed. The second lock may contend, depending on the
1487 * expected status. */
1488 for (i = 0;
1489 i < ARRAY_SIZE(zero_byte_tests);
1490 i++) {
1491 torture_comment(tctx, " ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1492 zero_byte_tests[i].lock1.pid,
1493 zero_byte_tests[i].lock1.offset,
1494 zero_byte_tests[i].lock1.count,
1495 zero_byte_tests[i].lock2.pid,
1496 zero_byte_tests[i].lock2.offset,
1497 zero_byte_tests[i].lock2.count,
1498 nt_errstr(zero_byte_tests[i].exp_status));
1500 /* Lock both locks. */
1501 io.lockx.in.ulock_cnt = 0;
1502 io.lockx.in.lock_cnt = 1;
1504 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1505 &zero_byte_tests[i].lock1);
1506 status = smb_raw_lock(cli->tree, &io);
1507 CHECK_STATUS(status, NT_STATUS_OK);
1509 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1510 &zero_byte_tests[i].lock2);
1511 status = smb_raw_lock(cli->tree, &io);
1513 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1514 NT_STATUS_LOCK_NOT_GRANTED)) {
1515 /* Allow either of the failure messages and keep going
1516 * if we see the wrong status. */
1517 CHECK_STATUS_OR_CONT(status,
1518 NT_STATUS_LOCK_NOT_GRANTED,
1519 NT_STATUS_FILE_LOCK_CONFLICT);
1521 } else {
1522 CHECK_STATUS_CONT(status,
1523 zero_byte_tests[i].exp_status);
1526 /* Unlock both locks. */
1527 io.lockx.in.ulock_cnt = 1;
1528 io.lockx.in.lock_cnt = 0;
1530 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1531 status = smb_raw_lock(cli->tree, &io);
1532 CHECK_STATUS(status, NT_STATUS_OK);
1535 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1536 &zero_byte_tests[i].lock1);
1537 status = smb_raw_lock(cli->tree, &io);
1538 CHECK_STATUS(status, NT_STATUS_OK);
1541 done:
1542 smbcli_close(cli->tree, fnum);
1543 smb_raw_exit(cli->session);
1544 smbcli_deltree(cli->tree, BASEDIR);
1545 return ret;
1548 static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1550 union smb_lock io;
1551 NTSTATUS status;
1552 bool ret = true;
1553 int fnum1, fnum2;
1554 const char *fname = BASEDIR "\\unlock.txt";
1555 struct smb_lock_entry lock1;
1556 struct smb_lock_entry lock2;
1558 torture_comment(tctx, "Testing LOCKX unlock:\n");
1560 if (!torture_setup_dir(cli, BASEDIR)) {
1561 return false;
1564 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1565 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1566 "Failed to create %s - %s\n",
1567 fname, smbcli_errstr(cli->tree)));
1569 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1570 torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1571 "Failed to create %s - %s\n",
1572 fname, smbcli_errstr(cli->tree)));
1574 /* Setup initial parameters */
1575 io.lockx.level = RAW_LOCK_LOCKX;
1576 io.lockx.in.timeout = 0;
1578 lock1.pid = cli->session->pid;
1579 lock1.offset = 0;
1580 lock1.count = 10;
1581 lock2.pid = cli->session->pid - 1;
1582 lock2.offset = 0;
1583 lock2.count = 10;
1586 * Take exclusive lock, then unlock it with a shared-unlock call.
1588 torture_comment(tctx, " taking exclusive lock.\n");
1589 io.lockx.in.ulock_cnt = 0;
1590 io.lockx.in.lock_cnt = 1;
1591 io.lockx.in.mode = 0;
1592 io.lockx.in.file.fnum = fnum1;
1593 io.lockx.in.locks = &lock1;
1594 status = smb_raw_lock(cli->tree, &io);
1595 CHECK_STATUS(status, NT_STATUS_OK);
1597 torture_comment(tctx, " unlock the exclusive with a shared unlock call.\n");
1598 io.lockx.in.ulock_cnt = 1;
1599 io.lockx.in.lock_cnt = 0;
1600 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1601 io.lockx.in.file.fnum = fnum1;
1602 io.lockx.in.locks = &lock1;
1603 status = smb_raw_lock(cli->tree, &io);
1604 CHECK_STATUS(status, NT_STATUS_OK);
1606 torture_comment(tctx, " try shared lock on pid2/fnum2, testing the unlock.\n");
1607 io.lockx.in.ulock_cnt = 0;
1608 io.lockx.in.lock_cnt = 1;
1609 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1610 io.lockx.in.file.fnum = fnum2;
1611 io.lockx.in.locks = &lock2;
1612 status = smb_raw_lock(cli->tree, &io);
1613 CHECK_STATUS(status, NT_STATUS_OK);
1616 * Unlock a shared lock with an exclusive-unlock call.
1618 torture_comment(tctx, " unlock new shared lock with exclusive unlock call.\n");
1619 io.lockx.in.ulock_cnt = 1;
1620 io.lockx.in.lock_cnt = 0;
1621 io.lockx.in.mode = 0;
1622 io.lockx.in.file.fnum = fnum2;
1623 io.lockx.in.locks = &lock2;
1624 status = smb_raw_lock(cli->tree, &io);
1625 CHECK_STATUS(status, NT_STATUS_OK);
1627 torture_comment(tctx, " try exclusive lock on pid1, testing the unlock.\n");
1628 io.lockx.in.ulock_cnt = 0;
1629 io.lockx.in.lock_cnt = 1;
1630 io.lockx.in.mode = 0;
1631 io.lockx.in.file.fnum = fnum1;
1632 io.lockx.in.locks = &lock1;
1633 status = smb_raw_lock(cli->tree, &io);
1634 CHECK_STATUS(status, NT_STATUS_OK);
1636 /* cleanup */
1637 io.lockx.in.ulock_cnt = 1;
1638 io.lockx.in.lock_cnt = 0;
1639 status = smb_raw_lock(cli->tree, &io);
1640 CHECK_STATUS(status, NT_STATUS_OK);
1643 * Test unlocking of 0-byte locks.
1646 torture_comment(tctx, " lock shared and exclusive 0-byte locks, testing that Windows "
1647 "always unlocks the exclusive first.\n");
1648 lock1.pid = cli->session->pid;
1649 lock1.offset = 10;
1650 lock1.count = 0;
1651 lock2.pid = cli->session->pid;
1652 lock2.offset = 5;
1653 lock2.count = 10;
1654 io.lockx.in.ulock_cnt = 0;
1655 io.lockx.in.lock_cnt = 1;
1656 io.lockx.in.file.fnum = fnum1;
1657 io.lockx.in.locks = &lock1;
1659 /* lock 0-byte shared
1660 * Note: Order of the shared/exclusive locks doesn't matter. */
1661 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1662 status = smb_raw_lock(cli->tree, &io);
1663 CHECK_STATUS(status, NT_STATUS_OK);
1665 /* lock 0-byte exclusive */
1666 io.lockx.in.mode = 0;
1667 status = smb_raw_lock(cli->tree, &io);
1668 CHECK_STATUS(status, NT_STATUS_OK);
1670 /* test contention */
1671 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1672 io.lockx.in.locks = &lock2;
1673 io.lockx.in.file.fnum = fnum2;
1674 status = smb_raw_lock(cli->tree, &io);
1675 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1676 NT_STATUS_FILE_LOCK_CONFLICT);
1678 /* unlock */
1679 io.lockx.in.ulock_cnt = 1;
1680 io.lockx.in.lock_cnt = 0;
1681 io.lockx.in.file.fnum = fnum1;
1682 io.lockx.in.locks = &lock1;
1683 status = smb_raw_lock(cli->tree, &io);
1684 CHECK_STATUS(status, NT_STATUS_OK);
1686 /* test - can we take a shared lock? */
1687 io.lockx.in.ulock_cnt = 0;
1688 io.lockx.in.lock_cnt = 1;
1689 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1690 io.lockx.in.file.fnum = fnum2;
1691 io.lockx.in.locks = &lock2;
1692 status = smb_raw_lock(cli->tree, &io);
1694 /* XXX Samba 3 will fail this test. This is temporary(because this isn't
1695 * new to Win7, it succeeds in WinXP too), until I can come to a
1696 * resolution as to whether Samba should support this or not. There is
1697 * code to preference unlocking exclusive locks before shared locks,
1698 * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1699 if (TARGET_IS_SAMBA3(tctx)) {
1700 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1701 NT_STATUS_FILE_LOCK_CONFLICT);
1702 } else {
1703 CHECK_STATUS(status, NT_STATUS_OK);
1706 /* cleanup */
1707 io.lockx.in.ulock_cnt = 1;
1708 io.lockx.in.lock_cnt = 0;
1709 status = smb_raw_lock(cli->tree, &io);
1711 /* XXX Same as above. */
1712 if (TARGET_IS_SAMBA3(tctx)) {
1713 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1714 } else {
1715 CHECK_STATUS(status, NT_STATUS_OK);
1718 io.lockx.in.file.fnum = fnum1;
1719 io.lockx.in.locks = &lock1;
1720 status = smb_raw_lock(cli->tree, &io);
1721 CHECK_STATUS(status, NT_STATUS_OK);
1723 done:
1724 smbcli_close(cli->tree, fnum1);
1725 smbcli_close(cli->tree, fnum2);
1726 smb_raw_exit(cli->session);
1727 smbcli_deltree(cli->tree, BASEDIR);
1728 return ret;
1731 static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1733 union smb_lock io;
1734 NTSTATUS status;
1735 bool ret = true;
1736 int fnum1;
1737 const char *fname = BASEDIR "\\unlock_multiple.txt";
1738 struct smb_lock_entry lock1;
1739 struct smb_lock_entry lock2;
1740 struct smb_lock_entry locks[2];
1742 torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1744 if (!torture_setup_dir(cli, BASEDIR)) {
1745 return false;
1748 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1749 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1750 "Failed to create %s - %s\n",
1751 fname, smbcli_errstr(cli->tree)));
1753 /* Setup initial parameters */
1754 io.lockx.level = RAW_LOCK_LOCKX;
1755 io.lockx.in.timeout = 0;
1757 lock1.pid = cli->session->pid;
1758 lock1.offset = 0;
1759 lock1.count = 10;
1760 lock2.pid = cli->session->pid;
1761 lock2.offset = 10;
1762 lock2.count = 10;
1764 locks[0] = lock1;
1765 locks[1] = lock2;
1767 io.lockx.in.file.fnum = fnum1;
1768 io.lockx.in.mode = 0; /* exclusive */
1770 /** Test1: Take second lock, but not first. */
1771 torture_comment(tctx, " unlock 2 locks, first one not locked. Expect no locks "
1772 "unlocked. \n");
1774 io.lockx.in.ulock_cnt = 0;
1775 io.lockx.in.lock_cnt = 1;
1776 io.lockx.in.locks = &lock2;
1777 status = smb_raw_lock(cli->tree, &io);
1778 CHECK_STATUS(status, NT_STATUS_OK);
1780 /* Try to unlock both locks. */
1781 io.lockx.in.ulock_cnt = 2;
1782 io.lockx.in.lock_cnt = 0;
1783 io.lockx.in.locks = locks;
1785 status = smb_raw_lock(cli->tree, &io);
1786 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1788 /* Second lock should not be unlocked. */
1789 io.lockx.in.ulock_cnt = 0;
1790 io.lockx.in.lock_cnt = 1;
1791 io.lockx.in.locks = &lock2;
1792 status = smb_raw_lock(cli->tree, &io);
1793 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1795 /* cleanup */
1796 io.lockx.in.ulock_cnt = 1;
1797 io.lockx.in.lock_cnt = 0;
1798 io.lockx.in.locks = &lock2;
1799 status = smb_raw_lock(cli->tree, &io);
1800 CHECK_STATUS(status, NT_STATUS_OK);
1802 /** Test2: Take first lock, but not second. */
1803 torture_comment(tctx, " unlock 2 locks, second one not locked. Expect first lock "
1804 "unlocked.\n");
1806 io.lockx.in.ulock_cnt = 0;
1807 io.lockx.in.lock_cnt = 1;
1808 io.lockx.in.locks = &lock1;
1809 status = smb_raw_lock(cli->tree, &io);
1810 CHECK_STATUS(status, NT_STATUS_OK);
1812 /* Try to unlock both locks. */
1813 io.lockx.in.ulock_cnt = 2;
1814 io.lockx.in.lock_cnt = 0;
1815 io.lockx.in.locks = locks;
1817 status = smb_raw_lock(cli->tree, &io);
1818 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1820 /* First lock should be unlocked. */
1821 io.lockx.in.ulock_cnt = 0;
1822 io.lockx.in.lock_cnt = 1;
1823 io.lockx.in.locks = &lock1;
1824 status = smb_raw_lock(cli->tree, &io);
1825 CHECK_STATUS(status, NT_STATUS_OK);
1827 /* cleanup */
1828 io.lockx.in.ulock_cnt = 1;
1829 io.lockx.in.lock_cnt = 0;
1830 io.lockx.in.locks = &lock1;
1831 status = smb_raw_lock(cli->tree, &io);
1832 CHECK_STATUS(status, NT_STATUS_OK);
1834 /* Test3: Request 2 locks, second will contend. What happens to the
1835 * first? */
1836 torture_comment(tctx, " request 2 locks, second one will contend. "
1837 "Expect both to fail.\n");
1839 /* Lock the second range */
1840 io.lockx.in.ulock_cnt = 0;
1841 io.lockx.in.lock_cnt = 1;
1842 io.lockx.in.locks = &lock2;
1843 status = smb_raw_lock(cli->tree, &io);
1844 CHECK_STATUS(status, NT_STATUS_OK);
1846 /* Request both locks */
1847 io.lockx.in.ulock_cnt = 0;
1848 io.lockx.in.lock_cnt = 2;
1849 io.lockx.in.locks = locks;
1851 status = smb_raw_lock(cli->tree, &io);
1852 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1854 /* First lock should be unlocked. */
1855 io.lockx.in.ulock_cnt = 0;
1856 io.lockx.in.lock_cnt = 1;
1857 io.lockx.in.locks = &lock1;
1858 status = smb_raw_lock(cli->tree, &io);
1859 CHECK_STATUS(status, NT_STATUS_OK);
1861 /* cleanup */
1862 io.lockx.in.ulock_cnt = 2;
1863 io.lockx.in.lock_cnt = 0;
1864 io.lockx.in.locks = locks;
1865 status = smb_raw_lock(cli->tree, &io);
1866 CHECK_STATUS(status, NT_STATUS_OK);
1868 /* Test4: Request unlock and lock. The lock contends, is the unlock
1869 * then re-locked? */
1870 torture_comment(tctx, " request unlock and lock, second one will "
1871 "contend. Expect the unlock to succeed.\n");
1873 /* Lock both ranges */
1874 io.lockx.in.ulock_cnt = 0;
1875 io.lockx.in.lock_cnt = 2;
1876 io.lockx.in.locks = locks;
1877 status = smb_raw_lock(cli->tree, &io);
1878 CHECK_STATUS(status, NT_STATUS_OK);
1880 /* Attempt to unlock the first range and lock the second */
1881 io.lockx.in.ulock_cnt = 1;
1882 io.lockx.in.lock_cnt = 1;
1883 io.lockx.in.locks = locks;
1884 status = smb_raw_lock(cli->tree, &io);
1885 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1887 /* The first lock should've been unlocked */
1888 io.lockx.in.ulock_cnt = 0;
1889 io.lockx.in.lock_cnt = 1;
1890 io.lockx.in.locks = &lock1;
1891 status = smb_raw_lock(cli->tree, &io);
1892 CHECK_STATUS(status, NT_STATUS_OK);
1894 /* cleanup */
1895 io.lockx.in.ulock_cnt = 2;
1896 io.lockx.in.lock_cnt = 0;
1897 io.lockx.in.locks = locks;
1898 status = smb_raw_lock(cli->tree, &io);
1899 CHECK_STATUS(status, NT_STATUS_OK);
1901 done:
1902 smbcli_close(cli->tree, fnum1);
1903 smb_raw_exit(cli->session);
1904 smbcli_deltree(cli->tree, BASEDIR);
1905 return ret;
1909 * torture_locktest5 covers stacking pretty well, but its missing two tests:
1910 * - stacking an exclusive on top of shared fails
1911 * - stacking two exclusives fail
1913 static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
1915 union smb_lock io;
1916 NTSTATUS status;
1917 bool ret = true;
1918 int fnum1;
1919 const char *fname = BASEDIR "\\stacking.txt";
1920 struct smb_lock_entry lock1;
1921 struct smb_lock_entry lock2;
1923 torture_comment(tctx, "Testing stacking:\n");
1925 if (!torture_setup_dir(cli, BASEDIR)) {
1926 return false;
1929 io.generic.level = RAW_LOCK_LOCKX;
1931 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1932 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1933 "Failed to create %s - %s\n",
1934 fname, smbcli_errstr(cli->tree)));
1936 /* Setup initial parameters */
1937 io.lockx.level = RAW_LOCK_LOCKX;
1938 io.lockx.in.timeout = 0;
1940 lock1.pid = cli->session->pid;
1941 lock1.offset = 0;
1942 lock1.count = 10;
1943 lock2.pid = cli->session->pid - 1;
1944 lock2.offset = 0;
1945 lock2.count = 10;
1948 * Try to take a shared lock, then stack an exclusive.
1950 torture_comment(tctx, " stacking an exclusive on top of a shared lock fails.\n");
1951 io.lockx.in.file.fnum = fnum1;
1952 io.lockx.in.locks = &lock1;
1954 io.lockx.in.ulock_cnt = 0;
1955 io.lockx.in.lock_cnt = 1;
1956 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1957 status = smb_raw_lock(cli->tree, &io);
1958 CHECK_STATUS(status, NT_STATUS_OK);
1960 io.lockx.in.ulock_cnt = 0;
1961 io.lockx.in.lock_cnt = 1;
1962 io.lockx.in.mode = 0;
1963 status = smb_raw_lock(cli->tree, &io);
1964 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1965 NT_STATUS_FILE_LOCK_CONFLICT);
1967 /* cleanup */
1968 io.lockx.in.ulock_cnt = 1;
1969 io.lockx.in.lock_cnt = 0;
1970 status = smb_raw_lock(cli->tree, &io);
1971 CHECK_STATUS(status, NT_STATUS_OK);
1974 * Prove that two exclusive locks do not stack.
1976 torture_comment(tctx, " two exclusive locks do not stack.\n");
1977 io.lockx.in.ulock_cnt = 0;
1978 io.lockx.in.lock_cnt = 1;
1979 io.lockx.in.mode = 0;
1980 status = smb_raw_lock(cli->tree, &io);
1981 CHECK_STATUS(status, NT_STATUS_OK);
1982 status = smb_raw_lock(cli->tree, &io);
1983 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1984 NT_STATUS_FILE_LOCK_CONFLICT);
1986 /* cleanup */
1987 io.lockx.in.ulock_cnt = 1;
1988 io.lockx.in.lock_cnt = 0;
1989 status = smb_raw_lock(cli->tree, &io);
1990 CHECK_STATUS(status, NT_STATUS_OK);
1992 done:
1993 smbcli_close(cli->tree, fnum1);
1994 smb_raw_exit(cli->session);
1995 smbcli_deltree(cli->tree, BASEDIR);
1996 return ret;
2000 basic testing of lock calls
2002 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
2004 struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
2006 torture_suite_add_1smb_test(suite, "lockx", test_lockx);
2007 torture_suite_add_1smb_test(suite, "lock", test_lock);
2008 torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
2009 torture_suite_add_1smb_test(suite, "async", test_async);
2010 torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
2011 torture_suite_add_1smb_test(suite, "changetype", test_changetype);
2013 torture_suite_add_1smb_test(suite, "stacking", test_stacking);
2014 torture_suite_add_1smb_test(suite, "unlock", test_unlock);
2015 torture_suite_add_1smb_test(suite, "multiple_unlock",
2016 test_multiple_unlock);
2017 torture_suite_add_1smb_test(suite, "zerobytelocks",
2018 test_zerobytelocks);
2020 return suite;