ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / torture / raw / lock.c
blob5a8714dc3a5b4f083ce1ad0e425dd2ad6b87d60f
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/cmdline.h"
31 #include "param/param.h"
32 #include "torture/raw/proto.h"
34 #define CHECK_STATUS(status, correct) do { \
35 if (!NT_STATUS_EQUAL(status, correct)) { \
36 torture_result(tctx, TORTURE_FAIL, \
37 "(%s) Incorrect status %s - should be %s\n", \
38 __location__, nt_errstr(status), nt_errstr(correct)); \
39 ret = false; \
40 goto done; \
41 }} while (0)
43 #define CHECK_STATUS_CONT(status, correct) do { \
44 if (!NT_STATUS_EQUAL(status, correct)) { \
45 torture_result(tctx, TORTURE_FAIL, \
46 "(%s) Incorrect status %s - should be %s\n", \
47 __location__, nt_errstr(status), nt_errstr(correct)); \
48 ret = false; \
49 }} while (0)
51 #define CHECK_STATUS_OR(status, correct1, correct2) do { \
52 if ((!NT_STATUS_EQUAL(status, correct1)) && \
53 (!NT_STATUS_EQUAL(status, correct2))) { \
54 torture_result(tctx, TORTURE_FAIL, \
55 "(%s) Incorrect status %s - should be %s or %s\n", \
56 __location__, nt_errstr(status), nt_errstr(correct1), \
57 nt_errstr(correct2)); \
58 ret = false; \
59 goto done; \
60 }} while (0)
62 #define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \
63 if ((!NT_STATUS_EQUAL(status, correct1)) && \
64 (!NT_STATUS_EQUAL(status, correct2))) { \
65 torture_result(tctx, TORTURE_FAIL, \
66 "(%s) Incorrect status %s - should be %s or %s\n", \
67 __location__, nt_errstr(status), nt_errstr(correct1), \
68 nt_errstr(correct2)); \
69 ret = false; \
70 }} while (0)
71 #define BASEDIR "\\testlock"
73 #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
74 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
75 #define TARGET_IS_WINDOWS(_tctx) \
76 ((torture_setting_bool(_tctx, "w2k3", false)) || \
77 (torture_setting_bool(_tctx, "w2k8", false)) || \
78 (torture_setting_bool(_tctx, "win7", false)))
79 #define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
80 #define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false))
82 #define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
83 (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
84 #define TARGET_SUPPORTS_SMBEXIT(_tctx) \
85 (torture_setting_bool(_tctx, "smbexit_pdu_support", true))
86 #define TARGET_SUPPORTS_SMBLOCK(_tctx) \
87 (torture_setting_bool(_tctx, "smblock_pdu_support", true))
88 #define TARGET_SUPPORTS_OPENX_DENY_DOS(_tctx) \
89 (torture_setting_bool(_tctx, "openx_deny_dos_support", true))
90 #define TARGET_RETURNS_RANGE_NOT_LOCKED(_tctx) \
91 (torture_setting_bool(_tctx, "range_not_locked_on_file_close", true))
93 test SMBlock and SMBunlock ops
95 static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
97 union smb_lock io;
98 NTSTATUS status;
99 bool ret = true;
100 int fnum;
101 const char *fname = BASEDIR "\\test.txt";
103 if (!TARGET_SUPPORTS_SMBLOCK(tctx))
104 torture_skip(tctx, "Target does not support the SMBlock PDU");
106 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
108 torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
109 io.generic.level = RAW_LOCK_LOCK;
111 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
112 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
113 "Failed to create %s - %s\n",
114 fname, smbcli_errstr(cli->tree)));
116 torture_comment(tctx, "Trying 0/0 lock\n");
117 io.lock.level = RAW_LOCK_LOCK;
118 io.lock.in.file.fnum = fnum;
119 io.lock.in.count = 0;
120 io.lock.in.offset = 0;
121 status = smb_raw_lock(cli->tree, &io);
122 CHECK_STATUS(status, NT_STATUS_OK);
123 cli->session->pid++;
124 status = smb_raw_lock(cli->tree, &io);
125 CHECK_STATUS(status, NT_STATUS_OK);
126 cli->session->pid--;
127 io.lock.level = RAW_LOCK_UNLOCK;
128 status = smb_raw_lock(cli->tree, &io);
129 CHECK_STATUS(status, NT_STATUS_OK);
131 torture_comment(tctx, "Trying 0/1 lock\n");
132 io.lock.level = RAW_LOCK_LOCK;
133 io.lock.in.file.fnum = fnum;
134 io.lock.in.count = 1;
135 io.lock.in.offset = 0;
136 status = smb_raw_lock(cli->tree, &io);
137 CHECK_STATUS(status, NT_STATUS_OK);
138 cli->session->pid++;
139 status = smb_raw_lock(cli->tree, &io);
140 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
141 cli->session->pid--;
142 io.lock.level = RAW_LOCK_UNLOCK;
143 status = smb_raw_lock(cli->tree, &io);
144 CHECK_STATUS(status, NT_STATUS_OK);
145 io.lock.level = RAW_LOCK_UNLOCK;
146 status = smb_raw_lock(cli->tree, &io);
147 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
149 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
150 io.lock.level = RAW_LOCK_LOCK;
151 io.lock.in.file.fnum = fnum;
152 io.lock.in.count = 4000;
153 io.lock.in.offset = 0xEEFFFFFF;
154 status = smb_raw_lock(cli->tree, &io);
155 CHECK_STATUS(status, NT_STATUS_OK);
156 cli->session->pid++;
157 status = smb_raw_lock(cli->tree, &io);
158 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
159 cli->session->pid--;
160 io.lock.level = RAW_LOCK_UNLOCK;
161 status = smb_raw_lock(cli->tree, &io);
162 CHECK_STATUS(status, NT_STATUS_OK);
163 io.lock.level = RAW_LOCK_UNLOCK;
164 status = smb_raw_lock(cli->tree, &io);
165 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
167 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
168 io.lock.level = RAW_LOCK_LOCK;
169 io.lock.in.file.fnum = fnum;
170 io.lock.in.count = 4000;
171 io.lock.in.offset = 0xEEFFFFFF;
172 status = smb_raw_lock(cli->tree, &io);
173 CHECK_STATUS(status, NT_STATUS_OK);
174 cli->session->pid++;
175 status = smb_raw_lock(cli->tree, &io);
176 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
177 cli->session->pid--;
178 io.lock.level = RAW_LOCK_UNLOCK;
179 status = smb_raw_lock(cli->tree, &io);
180 CHECK_STATUS(status, NT_STATUS_OK);
181 io.lock.level = RAW_LOCK_UNLOCK;
182 status = smb_raw_lock(cli->tree, &io);
183 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
185 torture_comment(tctx, "Trying max lock\n");
186 io.lock.level = RAW_LOCK_LOCK;
187 io.lock.in.file.fnum = fnum;
188 io.lock.in.count = 4000;
189 io.lock.in.offset = 0xEF000000;
190 status = smb_raw_lock(cli->tree, &io);
191 CHECK_STATUS(status, NT_STATUS_OK);
192 cli->session->pid++;
193 status = smb_raw_lock(cli->tree, &io);
194 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
195 cli->session->pid--;
196 io.lock.level = RAW_LOCK_UNLOCK;
197 status = smb_raw_lock(cli->tree, &io);
198 CHECK_STATUS(status, NT_STATUS_OK);
199 io.lock.level = RAW_LOCK_UNLOCK;
200 status = smb_raw_lock(cli->tree, &io);
201 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
203 torture_comment(tctx, "Trying wrong pid unlock\n");
204 io.lock.level = RAW_LOCK_LOCK;
205 io.lock.in.file.fnum = fnum;
206 io.lock.in.count = 4002;
207 io.lock.in.offset = 10001;
208 status = smb_raw_lock(cli->tree, &io);
209 CHECK_STATUS(status, NT_STATUS_OK);
210 cli->session->pid++;
211 io.lock.level = RAW_LOCK_UNLOCK;
212 status = smb_raw_lock(cli->tree, &io);
213 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
214 cli->session->pid--;
215 status = smb_raw_lock(cli->tree, &io);
216 CHECK_STATUS(status, NT_STATUS_OK);
218 done:
219 smbcli_close(cli->tree, fnum);
220 smb_raw_exit(cli->session);
221 smbcli_deltree(cli->tree, BASEDIR);
222 return ret;
227 test locking&X ops
229 static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
231 union smb_lock io;
232 struct smb_lock_entry lock[1];
233 NTSTATUS status;
234 bool ret = true;
235 int fnum;
236 const char *fname = BASEDIR "\\test.txt";
238 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
240 torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
241 io.generic.level = RAW_LOCK_LOCKX;
243 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
244 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
245 "Failed to create %s - %s\n",
246 fname, smbcli_errstr(cli->tree)));
248 io.lockx.level = RAW_LOCK_LOCKX;
249 io.lockx.in.file.fnum = fnum;
250 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
251 io.lockx.in.timeout = 0;
252 io.lockx.in.ulock_cnt = 0;
253 io.lockx.in.lock_cnt = 1;
254 lock[0].pid = cli->session->pid;
255 lock[0].offset = 10;
256 lock[0].count = 1;
257 io.lockx.in.locks = &lock[0];
258 status = smb_raw_lock(cli->tree, &io);
259 CHECK_STATUS(status, NT_STATUS_OK);
262 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
263 io.lockx.in.ulock_cnt = 0;
264 io.lockx.in.lock_cnt = 1;
265 lock[0].count = 4000;
266 lock[0].offset = 0xEEFFFFFF;
267 status = smb_raw_lock(cli->tree, &io);
268 CHECK_STATUS(status, NT_STATUS_OK);
269 lock[0].pid++;
270 status = smb_raw_lock(cli->tree, &io);
271 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
272 lock[0].pid--;
273 io.lockx.in.ulock_cnt = 1;
274 io.lockx.in.lock_cnt = 0;
275 status = smb_raw_lock(cli->tree, &io);
276 CHECK_STATUS(status, NT_STATUS_OK);
277 status = smb_raw_lock(cli->tree, &io);
278 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
280 torture_comment(tctx, "Trying 0xEF000000 lock\n");
281 io.lockx.in.ulock_cnt = 0;
282 io.lockx.in.lock_cnt = 1;
283 lock[0].count = 4000;
284 lock[0].offset = 0xEF000000;
285 status = smb_raw_lock(cli->tree, &io);
286 CHECK_STATUS(status, NT_STATUS_OK);
287 lock[0].pid++;
288 status = smb_raw_lock(cli->tree, &io);
289 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
290 lock[0].pid--;
291 io.lockx.in.ulock_cnt = 1;
292 io.lockx.in.lock_cnt = 0;
293 status = smb_raw_lock(cli->tree, &io);
294 CHECK_STATUS(status, NT_STATUS_OK);
295 status = smb_raw_lock(cli->tree, &io);
296 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
298 torture_comment(tctx, "Trying zero lock\n");
299 io.lockx.in.ulock_cnt = 0;
300 io.lockx.in.lock_cnt = 1;
301 lock[0].count = 0;
302 lock[0].offset = ~0;
303 status = smb_raw_lock(cli->tree, &io);
304 CHECK_STATUS(status, NT_STATUS_OK);
305 lock[0].pid++;
306 status = smb_raw_lock(cli->tree, &io);
307 CHECK_STATUS(status, NT_STATUS_OK);
308 lock[0].pid--;
309 io.lockx.in.ulock_cnt = 1;
310 io.lockx.in.lock_cnt = 0;
311 status = smb_raw_lock(cli->tree, &io);
312 CHECK_STATUS(status, NT_STATUS_OK);
313 status = smb_raw_lock(cli->tree, &io);
314 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
316 torture_comment(tctx, "Trying max lock\n");
317 io.lockx.in.ulock_cnt = 0;
318 io.lockx.in.lock_cnt = 1;
319 lock[0].count = 0;
320 lock[0].offset = ~0;
321 status = smb_raw_lock(cli->tree, &io);
322 CHECK_STATUS(status, NT_STATUS_OK);
323 lock[0].pid++;
324 status = smb_raw_lock(cli->tree, &io);
325 CHECK_STATUS(status, NT_STATUS_OK);
326 lock[0].pid--;
327 io.lockx.in.ulock_cnt = 1;
328 io.lockx.in.lock_cnt = 0;
329 status = smb_raw_lock(cli->tree, &io);
330 CHECK_STATUS(status, NT_STATUS_OK);
331 status = smb_raw_lock(cli->tree, &io);
332 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
334 torture_comment(tctx, "Trying 2^63\n");
335 io.lockx.in.ulock_cnt = 0;
336 io.lockx.in.lock_cnt = 1;
337 lock[0].count = 1;
338 lock[0].offset = 1;
339 lock[0].offset <<= 63;
340 status = smb_raw_lock(cli->tree, &io);
341 CHECK_STATUS(status, NT_STATUS_OK);
342 lock[0].pid++;
343 status = smb_raw_lock(cli->tree, &io);
344 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
345 lock[0].pid--;
346 io.lockx.in.ulock_cnt = 1;
347 io.lockx.in.lock_cnt = 0;
348 status = smb_raw_lock(cli->tree, &io);
349 CHECK_STATUS(status, NT_STATUS_OK);
350 status = smb_raw_lock(cli->tree, &io);
351 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
353 torture_comment(tctx, "Trying 2^63 - 1\n");
354 io.lockx.in.ulock_cnt = 0;
355 io.lockx.in.lock_cnt = 1;
356 lock[0].count = 1;
357 lock[0].offset = 1;
358 lock[0].offset <<= 63;
359 lock[0].offset--;
360 status = smb_raw_lock(cli->tree, &io);
361 CHECK_STATUS(status, NT_STATUS_OK);
362 lock[0].pid++;
363 status = smb_raw_lock(cli->tree, &io);
364 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
365 lock[0].pid--;
366 io.lockx.in.ulock_cnt = 1;
367 io.lockx.in.lock_cnt = 0;
368 status = smb_raw_lock(cli->tree, &io);
369 CHECK_STATUS(status, NT_STATUS_OK);
370 status = smb_raw_lock(cli->tree, &io);
371 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
373 torture_comment(tctx, "Trying max lock 2\n");
374 io.lockx.in.ulock_cnt = 0;
375 io.lockx.in.lock_cnt = 1;
376 lock[0].count = 1;
377 lock[0].offset = ~0;
378 status = smb_raw_lock(cli->tree, &io);
379 CHECK_STATUS(status, NT_STATUS_OK);
380 lock[0].pid++;
381 lock[0].count = 2;
382 status = smb_raw_lock(cli->tree, &io);
383 if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(tctx))
384 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
385 else
386 CHECK_STATUS(status, NT_STATUS_OK);
387 lock[0].pid--;
388 io.lockx.in.ulock_cnt = 1;
389 io.lockx.in.lock_cnt = 0;
390 lock[0].count = 1;
391 status = smb_raw_lock(cli->tree, &io);
393 CHECK_STATUS(status, NT_STATUS_OK);
394 status = smb_raw_lock(cli->tree, &io);
395 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
397 done:
398 smbcli_close(cli->tree, fnum);
399 smb_raw_exit(cli->session);
400 smbcli_deltree(cli->tree, BASEDIR);
401 return ret;
405 test high pid
407 static bool test_pidhigh(struct torture_context *tctx,
408 struct smbcli_state *cli)
410 union smb_lock io;
411 struct smb_lock_entry lock[1];
412 NTSTATUS status;
413 bool ret = true;
414 int fnum;
415 const char *fname = BASEDIR "\\test.txt";
416 uint8_t c = 1;
418 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
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 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
509 lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
511 torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
512 io.generic.level = RAW_LOCK_LOCKX;
514 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
515 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
516 "Failed to create %s - %s\n",
517 fname, smbcli_errstr(cli->tree)));
519 io.lockx.level = RAW_LOCK_LOCKX;
520 io.lockx.in.file.fnum = fnum;
521 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
522 io.lockx.in.timeout = 0;
523 io.lockx.in.ulock_cnt = 0;
524 io.lockx.in.lock_cnt = 1;
525 lock[0].pid = cli->session->pid;
526 lock[0].offset = 100;
527 lock[0].count = 10;
528 lock[1].pid = cli->session->pid;
529 lock[1].offset = 110;
530 lock[1].count = 10;
531 io.lockx.in.locks = &lock[0];
532 status = smb_raw_lock(cli->tree, &io);
533 CHECK_STATUS(status, NT_STATUS_OK);
535 t = time_mono(NULL);
537 torture_comment(tctx, "Testing cancel by CANCEL_LOCK\n");
539 /* setup a timed lock */
540 io.lockx.in.timeout = 10000;
541 req = smb_raw_lock_send(cli->tree, &io);
542 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
543 "Failed to setup timed lock (%s)\n", __location__));
545 /* cancel the wrong range */
546 lock[0].offset = 0;
547 io.lockx.in.timeout = 0;
548 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
549 status = smb_raw_lock(cli->tree, &io);
550 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
552 /* cancel with the wrong bits set */
553 lock[0].offset = 100;
554 io.lockx.in.timeout = 0;
555 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
556 status = smb_raw_lock(cli->tree, &io);
557 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
559 /* cancel the right range */
560 lock[0].offset = 100;
561 io.lockx.in.timeout = 0;
562 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
563 status = smb_raw_lock(cli->tree, &io);
564 CHECK_STATUS(status, NT_STATUS_OK);
566 /* receive the failed lock request */
567 status = smbcli_request_simple_recv(req);
568 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
570 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
571 "lock cancel was not immediate (%s)\n", __location__));
573 /* MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
574 * if the lock vector contains one entry. When given multiple cancel
575 * requests in a single PDU we expect the server to return an
576 * error. Samba4 handles this correctly. Windows servers seem to
577 * accept the request but only cancel the first lock. Samba3
578 * now does what Windows does (JRA).
580 torture_comment(tctx, "Testing multiple cancel\n");
582 /* acquire second lock */
583 io.lockx.in.timeout = 0;
584 io.lockx.in.ulock_cnt = 0;
585 io.lockx.in.lock_cnt = 1;
586 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
587 io.lockx.in.locks = &lock[1];
588 status = smb_raw_lock(cli->tree, &io);
589 CHECK_STATUS(status, NT_STATUS_OK);
591 /* setup 2 timed locks */
592 t = time_mono(NULL);
593 io.lockx.in.timeout = 10000;
594 io.lockx.in.lock_cnt = 1;
595 io.lockx.in.locks = &lock[0];
596 req = smb_raw_lock_send(cli->tree, &io);
597 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
598 "Failed to setup timed lock (%s)\n", __location__));
599 io.lockx.in.locks = &lock[1];
600 req2 = smb_raw_lock_send(cli->tree, &io);
601 torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
602 "Failed to setup timed lock (%s)\n", __location__));
604 /* try to cancel both locks in the same packet */
605 io.lockx.in.timeout = 0;
606 io.lockx.in.lock_cnt = 2;
607 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
608 io.lockx.in.locks = lock;
609 status = smb_raw_lock(cli->tree, &io);
610 CHECK_STATUS(status, NT_STATUS_OK);
612 torture_warning(tctx, "Target server accepted a lock cancel "
613 "request with multiple locks. This violates "
614 "MS-CIFS 2.2.4.32.1.\n");
616 /* receive the failed lock requests */
617 status = smbcli_request_simple_recv(req);
618 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
620 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
621 "first lock was not cancelled immediately (%s)\n",
622 __location__));
624 /* send cancel to second lock */
625 io.lockx.in.timeout = 0;
626 io.lockx.in.lock_cnt = 1;
627 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK |
628 LOCKING_ANDX_LARGE_FILES;
629 io.lockx.in.locks = &lock[1];
630 status = smb_raw_lock(cli->tree, &io);
631 CHECK_STATUS(status, NT_STATUS_OK);
633 status = smbcli_request_simple_recv(req2);
634 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
636 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
637 "second lock was not cancelled immediately (%s)\n",
638 __location__));
640 /* cleanup the second lock */
641 io.lockx.in.ulock_cnt = 1;
642 io.lockx.in.lock_cnt = 0;
643 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
644 io.lockx.in.locks = &lock[1];
645 status = smb_raw_lock(cli->tree, &io);
646 CHECK_STATUS(status, NT_STATUS_OK);
648 /* If a lock request contained multiple ranges and we are cancelling
649 * one while it's still pending, what happens? */
650 torture_comment(tctx, "Testing cancel 1/2 lock request\n");
652 /* Send request with two ranges */
653 io.lockx.in.timeout = -1;
654 io.lockx.in.ulock_cnt = 0;
655 io.lockx.in.lock_cnt = 2;
656 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
657 io.lockx.in.locks = lock;
658 req = smb_raw_lock_send(cli->tree, &io);
659 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
660 "Failed to setup pending lock (%s)\n", __location__));
662 /* Try to cancel the first lock range */
663 io.lockx.in.timeout = 0;
664 io.lockx.in.lock_cnt = 1;
665 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
666 io.lockx.in.locks = &lock[0];
667 status = smb_raw_lock(cli->tree, &io);
668 CHECK_STATUS(status, NT_STATUS_OK);
670 /* Locking request should've failed and second range should be
671 * unlocked */
672 status = smbcli_request_simple_recv(req);
673 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
675 io.lockx.in.timeout = 0;
676 io.lockx.in.ulock_cnt = 0;
677 io.lockx.in.lock_cnt = 1;
678 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
679 io.lockx.in.locks = &lock[1];
680 status = smb_raw_lock(cli->tree, &io);
681 CHECK_STATUS(status, NT_STATUS_OK);
683 /* Cleanup both locks */
684 io.lockx.in.ulock_cnt = 2;
685 io.lockx.in.lock_cnt = 0;
686 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
687 io.lockx.in.locks = lock;
688 status = smb_raw_lock(cli->tree, &io);
689 CHECK_STATUS(status, NT_STATUS_OK);
691 torture_comment(tctx, "Testing cancel 2/2 lock request\n");
693 /* Lock second range so it contends */
694 io.lockx.in.timeout = 0;
695 io.lockx.in.ulock_cnt = 0;
696 io.lockx.in.lock_cnt = 1;
697 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
698 io.lockx.in.locks = &lock[1];
699 status = smb_raw_lock(cli->tree, &io);
700 CHECK_STATUS(status, NT_STATUS_OK);
702 /* Send request with two ranges */
703 io.lockx.in.timeout = -1;
704 io.lockx.in.ulock_cnt = 0;
705 io.lockx.in.lock_cnt = 2;
706 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
707 io.lockx.in.locks = lock;
708 req = smb_raw_lock_send(cli->tree, &io);
709 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
710 "Failed to setup pending lock (%s)\n", __location__));
712 /* Try to cancel the second lock range */
713 io.lockx.in.timeout = 0;
714 io.lockx.in.lock_cnt = 1;
715 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
716 io.lockx.in.locks = &lock[1];
717 status = smb_raw_lock(cli->tree, &io);
718 CHECK_STATUS(status, NT_STATUS_OK);
720 /* Locking request should've failed and first range should be
721 * unlocked */
722 status = smbcli_request_simple_recv(req);
723 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
725 io.lockx.in.timeout = 0;
726 io.lockx.in.ulock_cnt = 0;
727 io.lockx.in.lock_cnt = 1;
728 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
729 io.lockx.in.locks = &lock[0];
730 status = smb_raw_lock(cli->tree, &io);
731 CHECK_STATUS(status, NT_STATUS_OK);
733 /* Cleanup both locks */
734 io.lockx.in.ulock_cnt = 2;
735 io.lockx.in.lock_cnt = 0;
736 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
737 io.lockx.in.locks = lock;
738 status = smb_raw_lock(cli->tree, &io);
739 CHECK_STATUS(status, NT_STATUS_OK);
741 torture_comment(tctx, "Testing cancel by unlock\n");
742 io.lockx.in.ulock_cnt = 0;
743 io.lockx.in.lock_cnt = 1;
744 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
745 io.lockx.in.timeout = 0;
746 io.lockx.in.locks = &lock[0];
747 status = smb_raw_lock(cli->tree, &io);
748 CHECK_STATUS(status, NT_STATUS_OK);
750 io.lockx.in.timeout = 5000;
751 req = smb_raw_lock_send(cli->tree, &io);
752 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
753 "Failed to setup timed lock (%s)\n", __location__));
755 io.lockx.in.ulock_cnt = 1;
756 io.lockx.in.lock_cnt = 0;
757 status = smb_raw_lock(cli->tree, &io);
758 CHECK_STATUS(status, NT_STATUS_OK);
760 t = time_mono(NULL);
761 status = smbcli_request_simple_recv(req);
762 CHECK_STATUS(status, NT_STATUS_OK);
764 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
765 "lock cancel by unlock was not immediate (%s) - took %d secs\n",
766 __location__, (int)(time_mono(NULL)-t)));
768 torture_comment(tctx, "Testing cancel by close\n");
769 io.lockx.in.ulock_cnt = 0;
770 io.lockx.in.lock_cnt = 1;
771 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
772 io.lockx.in.timeout = 0;
773 status = smb_raw_lock(cli->tree, &io);
774 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
778 * Make the test block on the second lock
779 * request. This is to regression-test 64c0367.
781 uint64_t tmp = lock[1].offset;
782 lock[1].offset = lock[0].offset;
783 lock[0].offset = tmp;
786 t = time_mono(NULL);
787 io.lockx.in.timeout = 10000;
788 io.lockx.in.lock_cnt = 2;
789 req = smb_raw_lock_send(cli->tree, &io);
790 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
791 "Failed to setup timed lock (%s)\n", __location__));
793 status = smbcli_close(cli->tree, fnum);
794 CHECK_STATUS(status, NT_STATUS_OK);
796 status = smbcli_request_simple_recv(req);
797 if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
798 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
799 else
800 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
802 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
803 "lock cancel by close was not immediate (%s)\n", __location__));
807 * Undo the change for 64c0367
809 uint64_t tmp = lock[1].offset;
810 lock[1].offset = lock[0].offset;
811 lock[0].offset = tmp;
814 torture_comment(tctx, "create a new sessions\n");
815 session = smbcli_session_init(cli->transport, tctx, false, options);
816 setup.in.sesskey = cli->transport->negotiate.sesskey;
817 setup.in.capabilities = cli->transport->negotiate.capabilities;
818 setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
819 setup.in.credentials = samba_cmdline_get_creds();
820 setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
821 status = smb_composite_sesssetup(session, &setup);
822 CHECK_STATUS(status, NT_STATUS_OK);
823 session->vuid = setup.out.vuid;
825 torture_comment(tctx, "create new tree context\n");
826 share = torture_setting_string(tctx, "share", NULL);
827 host = torture_setting_string(tctx, "host", NULL);
828 tree = smbcli_tree_init(session, tctx, false);
829 tcon.generic.level = RAW_TCON_TCONX;
830 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
831 tcon.tconx.in.password = data_blob(NULL, 0);
832 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
833 tcon.tconx.in.device = "A:";
834 status = smb_raw_tcon(tree, tctx, &tcon);
835 CHECK_STATUS(status, NT_STATUS_OK);
836 tree->tid = tcon.tconx.out.tid;
838 torture_comment(tctx, "Testing cancel by exit\n");
839 if (TARGET_SUPPORTS_SMBEXIT(tctx)) {
840 fname = BASEDIR "\\test_exit.txt";
841 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
842 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
843 "Failed to reopen %s - %s\n",
844 fname, smbcli_errstr(tree)));
846 io.lockx.level = RAW_LOCK_LOCKX;
847 io.lockx.in.file.fnum = fnum;
848 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
849 io.lockx.in.timeout = 0;
850 io.lockx.in.ulock_cnt = 0;
851 io.lockx.in.lock_cnt = 1;
852 lock[0].pid = session->pid;
853 lock[0].offset = 100;
854 lock[0].count = 10;
855 io.lockx.in.locks = &lock[0];
856 status = smb_raw_lock(tree, &io);
857 CHECK_STATUS(status, NT_STATUS_OK);
859 io.lockx.in.ulock_cnt = 0;
860 io.lockx.in.lock_cnt = 1;
861 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
862 io.lockx.in.timeout = 0;
863 status = smb_raw_lock(tree, &io);
864 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
866 io.lockx.in.timeout = 10000;
867 t = time_mono(NULL);
868 req = smb_raw_lock_send(tree, &io);
869 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
870 "Failed to setup timed lock (%s)\n",
871 __location__));
873 status = smb_raw_exit(session);
874 CHECK_STATUS(status, NT_STATUS_OK);
876 status = smbcli_request_simple_recv(req);
877 if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
878 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
879 else
880 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
882 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
883 "lock cancel by exit was not immediate (%s)\n",
884 __location__));
886 else {
887 torture_comment(tctx,
888 " skipping test, SMBExit not supported\n");
891 torture_comment(tctx, "Testing cancel by ulogoff\n");
892 fname = BASEDIR "\\test_ulogoff.txt";
893 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
894 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
895 "Failed to reopen %s - %s\n",
896 fname, smbcli_errstr(tree)));
898 io.lockx.level = RAW_LOCK_LOCKX;
899 io.lockx.in.file.fnum = fnum;
900 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
901 io.lockx.in.timeout = 0;
902 io.lockx.in.ulock_cnt = 0;
903 io.lockx.in.lock_cnt = 1;
904 lock[0].pid = session->pid;
905 lock[0].offset = 100;
906 lock[0].count = 10;
907 io.lockx.in.locks = &lock[0];
908 status = smb_raw_lock(tree, &io);
909 CHECK_STATUS(status, NT_STATUS_OK);
911 io.lockx.in.ulock_cnt = 0;
912 io.lockx.in.lock_cnt = 1;
913 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
914 io.lockx.in.timeout = 0;
915 status = smb_raw_lock(tree, &io);
916 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
918 io.lockx.in.timeout = 10000;
919 t = time_mono(NULL);
920 req = smb_raw_lock_send(tree, &io);
921 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
922 "Failed to setup timed lock (%s)\n", __location__));
924 status = smb_raw_ulogoff(session);
925 CHECK_STATUS(status, NT_STATUS_OK);
927 status = smbcli_request_simple_recv(req);
928 if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx)) {
929 if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
930 torture_result(tctx, TORTURE_FAIL,
931 "lock not canceled by ulogoff - %s "
932 "(ignored because of vfs_vifs fails it)\n",
933 nt_errstr(status));
934 smb_tree_disconnect(tree);
935 smb_raw_exit(session);
936 goto done;
938 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
939 } else {
940 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
943 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
944 "lock cancel by ulogoff was not immediate (%s)\n", __location__));
946 torture_comment(tctx, "Testing cancel by tdis\n");
947 tree->session = cli->session;
949 fname = BASEDIR "\\test_tdis.txt";
950 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
951 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
952 "Failed to reopen %s - %s\n",
953 fname, smbcli_errstr(tree)));
955 io.lockx.level = RAW_LOCK_LOCKX;
956 io.lockx.in.file.fnum = fnum;
957 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
958 io.lockx.in.timeout = 0;
959 io.lockx.in.ulock_cnt = 0;
960 io.lockx.in.lock_cnt = 1;
961 lock[0].pid = cli->session->pid;
962 lock[0].offset = 100;
963 lock[0].count = 10;
964 io.lockx.in.locks = &lock[0];
965 status = smb_raw_lock(tree, &io);
966 CHECK_STATUS(status, NT_STATUS_OK);
968 status = smb_raw_lock(tree, &io);
969 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
971 io.lockx.in.timeout = 10000;
972 t = time_mono(NULL);
973 req = smb_raw_lock_send(tree, &io);
974 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
975 "Failed to setup timed lock (%s)\n", __location__));
977 status = smb_tree_disconnect(tree);
978 CHECK_STATUS(status, NT_STATUS_OK);
980 status = smbcli_request_simple_recv(req);
981 if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
982 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
983 else
984 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
986 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
987 "lock cancel by tdis was not immediate (%s)\n", __location__));
989 done:
990 smb_raw_exit(cli->session);
991 smbcli_deltree(cli->tree, BASEDIR);
992 return ret;
996 test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
998 static bool test_errorcode(struct torture_context *tctx,
999 struct smbcli_state *cli)
1001 union smb_lock io;
1002 union smb_open op;
1003 struct smb_lock_entry lock[2];
1004 NTSTATUS status;
1005 bool ret = true;
1006 int fnum, fnum2;
1007 const char *fname;
1008 struct smbcli_request *req;
1009 time_t start;
1010 int t;
1011 int delay;
1012 uint16_t deny_mode = 0;
1014 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1016 torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
1018 torture_comment(tctx, "Testing with timeout = 0\n");
1019 fname = BASEDIR "\\test0.txt";
1020 t = 0;
1023 * the first run is with t = 0,
1024 * the second with t > 0 (=1)
1026 next_run:
1028 * use the DENY_DOS mode, that creates two fnum's of one low-level
1029 * file handle, this demonstrates that the cache is per fnum, not
1030 * per file handle
1032 if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
1033 deny_mode = OPENX_MODE_DENY_DOS;
1034 else
1035 deny_mode = OPENX_MODE_DENY_NONE;
1037 op.openx.level = RAW_OPEN_OPENX;
1038 op.openx.in.fname = fname;
1039 op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1040 op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
1041 op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
1042 op.openx.in.search_attrs = 0;
1043 op.openx.in.file_attrs = 0;
1044 op.openx.in.write_time = 0;
1045 op.openx.in.size = 0;
1046 op.openx.in.timeout = 0;
1048 status = smb_raw_open(cli->tree, tctx, &op);
1049 CHECK_STATUS(status, NT_STATUS_OK);
1050 fnum = op.openx.out.file.fnum;
1052 status = smb_raw_open(cli->tree, tctx, &op);
1053 CHECK_STATUS(status, NT_STATUS_OK);
1054 fnum2 = op.openx.out.file.fnum;
1056 io.lockx.level = RAW_LOCK_LOCKX;
1057 io.lockx.in.file.fnum = fnum;
1058 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1059 io.lockx.in.timeout = t;
1060 io.lockx.in.ulock_cnt = 0;
1061 io.lockx.in.lock_cnt = 1;
1062 lock[0].pid = cli->session->pid;
1063 lock[0].offset = 100;
1064 lock[0].count = 10;
1065 io.lockx.in.locks = &lock[0];
1066 status = smb_raw_lock(cli->tree, &io);
1067 CHECK_STATUS(status, NT_STATUS_OK);
1070 * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
1071 * this also demonstrates that the error code cache is per file handle
1072 * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
1074 io.lockx.in.file.fnum = fnum2;
1075 status = smb_raw_lock(cli->tree, &io);
1076 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1078 io.lockx.in.file.fnum = fnum;
1079 status = smb_raw_lock(cli->tree, &io);
1080 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1082 /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
1083 io.lockx.in.file.fnum = fnum;
1084 status = smb_raw_lock(cli->tree, &io);
1085 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1087 io.lockx.in.file.fnum = fnum2;
1088 status = smb_raw_lock(cli->tree, &io);
1089 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1091 io.lockx.in.file.fnum = fnum;
1092 status = smb_raw_lock(cli->tree, &io);
1093 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1095 io.lockx.in.file.fnum = fnum2;
1096 status = smb_raw_lock(cli->tree, &io);
1097 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1099 /* demonstrate that the smbpid doesn't matter */
1100 lock[0].pid++;
1101 io.lockx.in.file.fnum = fnum;
1102 status = smb_raw_lock(cli->tree, &io);
1103 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1105 io.lockx.in.file.fnum = fnum2;
1106 status = smb_raw_lock(cli->tree, &io);
1107 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1108 lock[0].pid--;
1111 * demonstrate that a successful lock with count = 0 and the same offset,
1112 * doesn't reset the error cache
1114 lock[0].offset = 100;
1115 lock[0].count = 0;
1116 io.lockx.in.file.fnum = fnum;
1117 status = smb_raw_lock(cli->tree, &io);
1118 CHECK_STATUS(status, NT_STATUS_OK);
1120 io.lockx.in.file.fnum = fnum2;
1121 status = smb_raw_lock(cli->tree, &io);
1122 CHECK_STATUS(status, NT_STATUS_OK);
1124 lock[0].offset = 100;
1125 lock[0].count = 10;
1126 io.lockx.in.file.fnum = fnum;
1127 status = smb_raw_lock(cli->tree, &io);
1128 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1130 io.lockx.in.file.fnum = fnum2;
1131 status = smb_raw_lock(cli->tree, &io);
1132 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1135 * demonstrate that a successful lock with count = 0 and outside the locked range,
1136 * doesn't reset the error cache
1138 lock[0].offset = 110;
1139 lock[0].count = 0;
1140 io.lockx.in.file.fnum = fnum;
1141 status = smb_raw_lock(cli->tree, &io);
1142 CHECK_STATUS(status, NT_STATUS_OK);
1144 io.lockx.in.file.fnum = fnum2;
1145 status = smb_raw_lock(cli->tree, &io);
1146 CHECK_STATUS(status, NT_STATUS_OK);
1148 lock[0].offset = 100;
1149 lock[0].count = 10;
1150 io.lockx.in.file.fnum = fnum;
1151 status = smb_raw_lock(cli->tree, &io);
1152 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1154 io.lockx.in.file.fnum = fnum2;
1155 status = smb_raw_lock(cli->tree, &io);
1156 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1158 lock[0].offset = 99;
1159 lock[0].count = 0;
1160 io.lockx.in.file.fnum = fnum;
1161 status = smb_raw_lock(cli->tree, &io);
1162 CHECK_STATUS(status, NT_STATUS_OK);
1164 io.lockx.in.file.fnum = fnum2;
1165 status = smb_raw_lock(cli->tree, &io);
1166 CHECK_STATUS(status, NT_STATUS_OK);
1168 lock[0].offset = 100;
1169 lock[0].count = 10;
1170 io.lockx.in.file.fnum = fnum;
1171 status = smb_raw_lock(cli->tree, &io);
1172 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1174 io.lockx.in.file.fnum = fnum2;
1175 status = smb_raw_lock(cli->tree, &io);
1176 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1178 /* demonstrate that a changing count doesn't reset the error cache */
1179 lock[0].offset = 100;
1180 lock[0].count = 5;
1181 io.lockx.in.file.fnum = fnum;
1182 status = smb_raw_lock(cli->tree, &io);
1183 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1185 io.lockx.in.file.fnum = fnum2;
1186 status = smb_raw_lock(cli->tree, &io);
1187 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1189 lock[0].offset = 100;
1190 lock[0].count = 15;
1191 io.lockx.in.file.fnum = fnum;
1192 status = smb_raw_lock(cli->tree, &io);
1193 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1195 io.lockx.in.file.fnum = fnum2;
1196 status = smb_raw_lock(cli->tree, &io);
1197 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1200 * demonstrate that a lock with count = 0 and inside the locked range,
1201 * fails and resets the error cache
1203 lock[0].offset = 101;
1204 lock[0].count = 0;
1205 io.lockx.in.file.fnum = fnum;
1206 status = smb_raw_lock(cli->tree, &io);
1207 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1208 status = smb_raw_lock(cli->tree, &io);
1209 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1211 io.lockx.in.file.fnum = fnum2;
1212 status = smb_raw_lock(cli->tree, &io);
1213 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1214 status = smb_raw_lock(cli->tree, &io);
1215 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1217 lock[0].offset = 100;
1218 lock[0].count = 10;
1219 io.lockx.in.file.fnum = fnum;
1220 status = smb_raw_lock(cli->tree, &io);
1221 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1222 status = smb_raw_lock(cli->tree, &io);
1223 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1225 io.lockx.in.file.fnum = fnum2;
1226 status = smb_raw_lock(cli->tree, &io);
1227 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1228 status = smb_raw_lock(cli->tree, &io);
1229 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1231 /* demonstrate that a changing offset resets the error cache */
1232 lock[0].offset = 105;
1233 lock[0].count = 10;
1234 io.lockx.in.file.fnum = fnum;
1235 status = smb_raw_lock(cli->tree, &io);
1236 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1237 status = smb_raw_lock(cli->tree, &io);
1238 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1240 io.lockx.in.file.fnum = fnum2;
1241 status = smb_raw_lock(cli->tree, &io);
1242 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1243 status = smb_raw_lock(cli->tree, &io);
1244 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1246 lock[0].offset = 100;
1247 lock[0].count = 10;
1248 io.lockx.in.file.fnum = fnum;
1249 status = smb_raw_lock(cli->tree, &io);
1250 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1251 status = smb_raw_lock(cli->tree, &io);
1252 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1254 io.lockx.in.file.fnum = fnum2;
1255 status = smb_raw_lock(cli->tree, &io);
1256 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1257 status = smb_raw_lock(cli->tree, &io);
1258 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1260 lock[0].offset = 95;
1261 lock[0].count = 9;
1262 io.lockx.in.file.fnum = fnum;
1263 status = smb_raw_lock(cli->tree, &io);
1264 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1265 status = smb_raw_lock(cli->tree, &io);
1266 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1268 io.lockx.in.file.fnum = fnum2;
1269 status = smb_raw_lock(cli->tree, &io);
1270 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1271 status = smb_raw_lock(cli->tree, &io);
1272 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1274 lock[0].offset = 100;
1275 lock[0].count = 10;
1276 io.lockx.in.file.fnum = fnum;
1277 status = smb_raw_lock(cli->tree, &io);
1278 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1279 status = smb_raw_lock(cli->tree, &io);
1280 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1282 io.lockx.in.file.fnum = fnum2;
1283 status = smb_raw_lock(cli->tree, &io);
1284 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1285 status = smb_raw_lock(cli->tree, &io);
1286 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1289 * demonstrate that a successful lock in a different range
1290 * doesn't reset the cache, the failing lock on the 2nd handle
1291 * resets the cache
1293 lock[0].offset = 120;
1294 lock[0].count = 15;
1295 io.lockx.in.file.fnum = fnum;
1296 status = smb_raw_lock(cli->tree, &io);
1297 CHECK_STATUS(status, NT_STATUS_OK);
1299 io.lockx.in.file.fnum = fnum2;
1300 status = smb_raw_lock(cli->tree, &io);
1301 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1303 lock[0].offset = 100;
1304 lock[0].count = 10;
1305 io.lockx.in.file.fnum = fnum;
1306 status = smb_raw_lock(cli->tree, &io);
1307 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1308 status = smb_raw_lock(cli->tree, &io);
1309 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1311 io.lockx.in.file.fnum = fnum2;
1312 status = smb_raw_lock(cli->tree, &io);
1313 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1314 status = smb_raw_lock(cli->tree, &io);
1315 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1317 /* end of the loop */
1318 if (t == 0) {
1319 smb_raw_exit(cli->session);
1320 t = 1;
1321 torture_comment(tctx, "Testing with timeout > 0 (=%d)\n",
1323 fname = BASEDIR "\\test1.txt";
1324 goto next_run;
1327 t = 4000;
1328 torture_comment(tctx, "Testing special cases with timeout > 0 (=%d)\n",
1332 * the following 3 test sections demonstrate that
1333 * the cache is only set when the error is reported
1334 * to the client (after the timeout went by)
1336 smb_raw_exit(cli->session);
1337 torture_comment(tctx, "Testing a conflict while a lock is pending\n");
1338 fname = BASEDIR "\\test2.txt";
1339 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1340 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1341 "Failed to reopen %s - %s\n",
1342 fname, smbcli_errstr(cli->tree)));
1344 io.lockx.level = RAW_LOCK_LOCKX;
1345 io.lockx.in.file.fnum = fnum;
1346 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1347 io.lockx.in.timeout = 0;
1348 io.lockx.in.ulock_cnt = 0;
1349 io.lockx.in.lock_cnt = 1;
1350 lock[0].pid = cli->session->pid;
1351 lock[0].offset = 100;
1352 lock[0].count = 10;
1353 io.lockx.in.locks = &lock[0];
1354 status = smb_raw_lock(cli->tree, &io);
1355 CHECK_STATUS(status, NT_STATUS_OK);
1357 start = time_mono(NULL);
1358 io.lockx.in.timeout = t;
1359 req = smb_raw_lock_send(cli->tree, &io);
1360 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1361 "Failed to setup timed lock (%s)\n", __location__));
1363 io.lockx.in.timeout = 0;
1364 lock[0].offset = 105;
1365 lock[0].count = 10;
1366 status = smb_raw_lock(cli->tree, &io);
1367 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1369 status = smbcli_request_simple_recv(req);
1370 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1372 delay = t / 1000;
1373 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1374 delay /= 2;
1377 torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
1378 "lock comes back to early timeout[%d] delay[%d]"
1379 "(%s)\n", t, delay, __location__));
1381 status = smb_raw_lock(cli->tree, &io);
1382 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1384 smbcli_close(cli->tree, fnum);
1385 fname = BASEDIR "\\test3.txt";
1386 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1387 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1388 "Failed to reopen %s - %s\n",
1389 fname, smbcli_errstr(cli->tree)));
1391 io.lockx.level = RAW_LOCK_LOCKX;
1392 io.lockx.in.file.fnum = fnum;
1393 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1394 io.lockx.in.timeout = 0;
1395 io.lockx.in.ulock_cnt = 0;
1396 io.lockx.in.lock_cnt = 1;
1397 lock[0].pid = cli->session->pid;
1398 lock[0].offset = 100;
1399 lock[0].count = 10;
1400 io.lockx.in.locks = &lock[0];
1401 status = smb_raw_lock(cli->tree, &io);
1402 CHECK_STATUS(status, NT_STATUS_OK);
1404 start = time_mono(NULL);
1405 io.lockx.in.timeout = t;
1406 req = smb_raw_lock_send(cli->tree, &io);
1407 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1408 "Failed to setup timed lock (%s)\n", __location__));
1410 io.lockx.in.timeout = 0;
1411 lock[0].offset = 105;
1412 lock[0].count = 10;
1413 status = smb_raw_lock(cli->tree, &io);
1414 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1416 status = smbcli_request_simple_recv(req);
1417 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1419 delay = t / 1000;
1420 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1421 delay /= 2;
1424 torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
1425 "lock comes back to early timeout[%d] delay[%d]"
1426 "(%s)\n", t, delay, __location__));
1428 lock[0].offset = 100;
1429 lock[0].count = 10;
1430 status = smb_raw_lock(cli->tree, &io);
1431 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1433 smbcli_close(cli->tree, fnum);
1434 fname = BASEDIR "\\test4.txt";
1435 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1436 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1437 "Failed to reopen %s - %s\n",
1438 fname, smbcli_errstr(cli->tree)));
1440 io.lockx.level = RAW_LOCK_LOCKX;
1441 io.lockx.in.file.fnum = fnum;
1442 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1443 io.lockx.in.timeout = 0;
1444 io.lockx.in.ulock_cnt = 0;
1445 io.lockx.in.lock_cnt = 1;
1446 lock[0].pid = cli->session->pid;
1447 lock[0].offset = 100;
1448 lock[0].count = 10;
1449 io.lockx.in.locks = &lock[0];
1450 status = smb_raw_lock(cli->tree, &io);
1451 CHECK_STATUS(status, NT_STATUS_OK);
1453 start = time_mono(NULL);
1454 io.lockx.in.timeout = t;
1455 req = smb_raw_lock_send(cli->tree, &io);
1456 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1457 "Failed to setup timed lock (%s)\n", __location__));
1459 io.lockx.in.timeout = 0;
1460 status = smb_raw_lock(cli->tree, &io);
1461 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1463 status = smbcli_request_simple_recv(req);
1464 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1466 delay = t / 1000;
1467 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1468 delay /= 2;
1471 torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
1472 "lock comes back to early timeout[%d] delay[%d]"
1473 "(%s)\n", t, delay, __location__));
1475 status = smb_raw_lock(cli->tree, &io);
1476 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1478 done:
1479 smb_raw_exit(cli->session);
1480 smbcli_deltree(cli->tree, BASEDIR);
1481 return ret;
1486 test LOCKING_ANDX_CHANGE_LOCKTYPE
1488 static bool test_changetype(struct torture_context *tctx,
1489 struct smbcli_state *cli)
1491 union smb_lock io;
1492 struct smb_lock_entry lock[2];
1493 NTSTATUS status;
1494 bool ret = true;
1495 int fnum;
1496 uint8_t c = 0;
1497 const char *fname = BASEDIR "\\test.txt";
1499 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1501 torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1502 io.generic.level = RAW_LOCK_LOCKX;
1504 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1505 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1506 "Failed to create %s - %s\n",
1507 fname, smbcli_errstr(cli->tree)));
1509 io.lockx.level = RAW_LOCK_LOCKX;
1510 io.lockx.in.file.fnum = fnum;
1511 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1512 io.lockx.in.timeout = 0;
1513 io.lockx.in.ulock_cnt = 0;
1514 io.lockx.in.lock_cnt = 1;
1515 lock[0].pid = cli->session->pid;
1516 lock[0].offset = 100;
1517 lock[0].count = 10;
1518 io.lockx.in.locks = &lock[0];
1519 status = smb_raw_lock(cli->tree, &io);
1520 CHECK_STATUS(status, NT_STATUS_OK);
1522 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1523 torture_result(tctx, TORTURE_FAIL,
1524 "allowed write on read locked region (%s)\n", __location__);
1525 ret = false;
1526 goto done;
1529 /* windows server don't seem to support this */
1530 io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1531 status = smb_raw_lock(cli->tree, &io);
1532 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1534 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1535 torture_result(tctx, TORTURE_FAIL,
1536 "allowed write after lock change (%s)\n", __location__);
1537 ret = false;
1538 goto done;
1541 done:
1542 smbcli_close(cli->tree, fnum);
1543 smb_raw_exit(cli->session);
1544 smbcli_deltree(cli->tree, BASEDIR);
1545 return ret;
1548 struct double_lock_test {
1549 struct smb_lock_entry lock1;
1550 struct smb_lock_entry lock2;
1551 NTSTATUS exp_status;
1555 * Tests zero byte locks.
1557 static struct double_lock_test zero_byte_tests[] = {
1558 /* {pid, offset, count}, {pid, offset, count}, status */
1560 /** First, takes a zero byte lock at offset 10. Then:
1561 * - Taking 0 byte lock at 10 should succeed.
1562 * - Taking 1 byte locks at 9,10,11 should succeed.
1563 * - Taking 2 byte lock at 9 should fail.
1564 * - Taking 2 byte lock at 10 should succeed.
1565 * - Taking 3 byte lock at 9 should fail.
1567 {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1568 {{1000, 10, 0}, {1001, 9, 1}, NT_STATUS_OK},
1569 {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1570 {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1571 {{1000, 10, 0}, {1001, 9, 2}, NT_STATUS_LOCK_NOT_GRANTED},
1572 {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1573 {{1000, 10, 0}, {1001, 9, 3}, NT_STATUS_LOCK_NOT_GRANTED},
1575 /** Same, but opposite order. */
1576 {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1577 {{1001, 9, 1}, {1000, 10, 0}, NT_STATUS_OK},
1578 {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1579 {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1580 {{1001, 9, 2}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1581 {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1582 {{1001, 9, 3}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1584 /** Zero zero case. */
1585 {{1000, 0, 0}, {1001, 0, 0}, NT_STATUS_OK},
1588 static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1590 union smb_lock io;
1591 NTSTATUS status;
1592 bool ret = true;
1593 int fnum, i;
1594 const char *fname = BASEDIR "\\zero.txt";
1596 torture_comment(tctx, "Testing zero length byte range locks:\n");
1598 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1600 io.generic.level = RAW_LOCK_LOCKX;
1602 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1603 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1604 "Failed to create %s - %s\n",
1605 fname, smbcli_errstr(cli->tree)));
1607 /* Setup initial parameters */
1608 io.lockx.level = RAW_LOCK_LOCKX;
1609 io.lockx.in.file.fnum = fnum;
1610 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1611 io.lockx.in.timeout = 0;
1613 /* Try every combination of locks in zero_byte_tests. The first lock is
1614 * assumed to succeed. The second lock may contend, depending on the
1615 * expected status. */
1616 for (i = 0;
1617 i < ARRAY_SIZE(zero_byte_tests);
1618 i++) {
1619 torture_comment(tctx, " ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1620 zero_byte_tests[i].lock1.pid,
1621 (unsigned long long) zero_byte_tests[i].lock1.offset,
1622 (unsigned long long) zero_byte_tests[i].lock1.count,
1623 zero_byte_tests[i].lock2.pid,
1624 (unsigned long long) zero_byte_tests[i].lock2.offset,
1625 (unsigned long long) zero_byte_tests[i].lock2.count,
1626 nt_errstr(zero_byte_tests[i].exp_status));
1628 /* Lock both locks. */
1629 io.lockx.in.ulock_cnt = 0;
1630 io.lockx.in.lock_cnt = 1;
1632 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1633 &zero_byte_tests[i].lock1);
1634 status = smb_raw_lock(cli->tree, &io);
1635 CHECK_STATUS(status, NT_STATUS_OK);
1637 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1638 &zero_byte_tests[i].lock2);
1639 status = smb_raw_lock(cli->tree, &io);
1641 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1642 NT_STATUS_LOCK_NOT_GRANTED)) {
1643 /* Allow either of the failure messages and keep going
1644 * if we see the wrong status. */
1645 CHECK_STATUS_OR_CONT(status,
1646 NT_STATUS_LOCK_NOT_GRANTED,
1647 NT_STATUS_FILE_LOCK_CONFLICT);
1649 } else {
1650 CHECK_STATUS_CONT(status,
1651 zero_byte_tests[i].exp_status);
1654 /* Unlock both locks. */
1655 io.lockx.in.ulock_cnt = 1;
1656 io.lockx.in.lock_cnt = 0;
1658 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1659 status = smb_raw_lock(cli->tree, &io);
1660 CHECK_STATUS(status, NT_STATUS_OK);
1663 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1664 &zero_byte_tests[i].lock1);
1665 status = smb_raw_lock(cli->tree, &io);
1666 CHECK_STATUS(status, NT_STATUS_OK);
1669 done:
1670 smbcli_close(cli->tree, fnum);
1671 smb_raw_exit(cli->session);
1672 smbcli_deltree(cli->tree, BASEDIR);
1673 return ret;
1676 static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1678 union smb_lock io;
1679 NTSTATUS status;
1680 bool ret = true;
1681 int fnum1, fnum2;
1682 const char *fname = BASEDIR "\\unlock.txt";
1683 struct smb_lock_entry lock1;
1684 struct smb_lock_entry lock2;
1686 torture_comment(tctx, "Testing LOCKX unlock:\n");
1688 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1690 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1691 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1692 "Failed to create %s - %s\n",
1693 fname, smbcli_errstr(cli->tree)));
1695 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1696 torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1697 "Failed to create %s - %s\n",
1698 fname, smbcli_errstr(cli->tree)));
1700 /* Setup initial parameters */
1701 io.lockx.level = RAW_LOCK_LOCKX;
1702 io.lockx.in.timeout = 0;
1704 lock1.pid = cli->session->pid;
1705 lock1.offset = 0;
1706 lock1.count = 10;
1707 lock2.pid = cli->session->pid - 1;
1708 lock2.offset = 0;
1709 lock2.count = 10;
1712 * Take exclusive lock, then unlock it with a shared-unlock call.
1714 torture_comment(tctx, " taking exclusive lock.\n");
1715 io.lockx.in.ulock_cnt = 0;
1716 io.lockx.in.lock_cnt = 1;
1717 io.lockx.in.mode = 0;
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 torture_comment(tctx, " unlock the exclusive with a shared unlock call.\n");
1724 io.lockx.in.ulock_cnt = 1;
1725 io.lockx.in.lock_cnt = 0;
1726 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1727 io.lockx.in.file.fnum = fnum1;
1728 io.lockx.in.locks = &lock1;
1729 status = smb_raw_lock(cli->tree, &io);
1730 CHECK_STATUS(status, NT_STATUS_OK);
1732 torture_comment(tctx, " try shared lock on pid2/fnum2, testing the unlock.\n");
1733 io.lockx.in.ulock_cnt = 0;
1734 io.lockx.in.lock_cnt = 1;
1735 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1736 io.lockx.in.file.fnum = fnum2;
1737 io.lockx.in.locks = &lock2;
1738 status = smb_raw_lock(cli->tree, &io);
1739 CHECK_STATUS(status, NT_STATUS_OK);
1742 * Unlock a shared lock with an exclusive-unlock call.
1744 torture_comment(tctx, " unlock new shared lock with exclusive unlock call.\n");
1745 io.lockx.in.ulock_cnt = 1;
1746 io.lockx.in.lock_cnt = 0;
1747 io.lockx.in.mode = 0;
1748 io.lockx.in.file.fnum = fnum2;
1749 io.lockx.in.locks = &lock2;
1750 status = smb_raw_lock(cli->tree, &io);
1751 CHECK_STATUS(status, NT_STATUS_OK);
1753 torture_comment(tctx, " try exclusive lock on pid1, testing the unlock.\n");
1754 io.lockx.in.ulock_cnt = 0;
1755 io.lockx.in.lock_cnt = 1;
1756 io.lockx.in.mode = 0;
1757 io.lockx.in.file.fnum = fnum1;
1758 io.lockx.in.locks = &lock1;
1759 status = smb_raw_lock(cli->tree, &io);
1760 CHECK_STATUS(status, NT_STATUS_OK);
1762 /* cleanup */
1763 io.lockx.in.ulock_cnt = 1;
1764 io.lockx.in.lock_cnt = 0;
1765 status = smb_raw_lock(cli->tree, &io);
1766 CHECK_STATUS(status, NT_STATUS_OK);
1769 * Test unlocking of 0-byte locks.
1772 torture_comment(tctx, " lock shared and exclusive 0-byte locks, testing that Windows "
1773 "always unlocks the exclusive first.\n");
1774 lock1.pid = cli->session->pid;
1775 lock1.offset = 10;
1776 lock1.count = 0;
1777 lock2.pid = cli->session->pid;
1778 lock2.offset = 5;
1779 lock2.count = 10;
1780 io.lockx.in.ulock_cnt = 0;
1781 io.lockx.in.lock_cnt = 1;
1782 io.lockx.in.file.fnum = fnum1;
1783 io.lockx.in.locks = &lock1;
1785 /* lock 0-byte shared
1786 * Note: Order of the shared/exclusive locks doesn't matter. */
1787 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1788 status = smb_raw_lock(cli->tree, &io);
1789 CHECK_STATUS(status, NT_STATUS_OK);
1791 /* lock 0-byte exclusive */
1792 io.lockx.in.mode = 0;
1793 status = smb_raw_lock(cli->tree, &io);
1794 CHECK_STATUS(status, NT_STATUS_OK);
1796 /* test contention */
1797 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1798 io.lockx.in.locks = &lock2;
1799 io.lockx.in.file.fnum = fnum2;
1800 status = smb_raw_lock(cli->tree, &io);
1801 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1802 NT_STATUS_FILE_LOCK_CONFLICT);
1804 /* unlock */
1805 io.lockx.in.ulock_cnt = 1;
1806 io.lockx.in.lock_cnt = 0;
1807 io.lockx.in.file.fnum = fnum1;
1808 io.lockx.in.locks = &lock1;
1809 status = smb_raw_lock(cli->tree, &io);
1810 CHECK_STATUS(status, NT_STATUS_OK);
1812 /* test - can we take a shared lock? */
1813 io.lockx.in.ulock_cnt = 0;
1814 io.lockx.in.lock_cnt = 1;
1815 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1816 io.lockx.in.file.fnum = fnum2;
1817 io.lockx.in.locks = &lock2;
1818 status = smb_raw_lock(cli->tree, &io);
1820 /* XXX Samba 3 will fail this test. This is temporary(because this isn't
1821 * new to Win7, it succeeds in WinXP too), until I can come to a
1822 * resolution as to whether Samba should support this or not. There is
1823 * code to preference unlocking exclusive locks before shared locks,
1824 * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1825 if (TARGET_IS_SAMBA3(tctx)) {
1826 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1827 NT_STATUS_FILE_LOCK_CONFLICT);
1828 } else {
1829 CHECK_STATUS(status, NT_STATUS_OK);
1832 /* cleanup */
1833 io.lockx.in.ulock_cnt = 1;
1834 io.lockx.in.lock_cnt = 0;
1835 status = smb_raw_lock(cli->tree, &io);
1837 /* XXX Same as above. */
1838 if (TARGET_IS_SAMBA3(tctx)) {
1839 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1840 } else {
1841 CHECK_STATUS(status, NT_STATUS_OK);
1844 io.lockx.in.file.fnum = fnum1;
1845 io.lockx.in.locks = &lock1;
1846 status = smb_raw_lock(cli->tree, &io);
1847 CHECK_STATUS(status, NT_STATUS_OK);
1849 done:
1850 smbcli_close(cli->tree, fnum1);
1851 smbcli_close(cli->tree, fnum2);
1852 smb_raw_exit(cli->session);
1853 smbcli_deltree(cli->tree, BASEDIR);
1854 return ret;
1857 static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1859 union smb_lock io;
1860 NTSTATUS status;
1861 bool ret = true;
1862 int fnum1;
1863 const char *fname = BASEDIR "\\unlock_multiple.txt";
1864 struct smb_lock_entry lock1;
1865 struct smb_lock_entry lock2;
1866 struct smb_lock_entry locks[2];
1868 torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1870 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1872 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1873 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1874 "Failed to create %s - %s\n",
1875 fname, smbcli_errstr(cli->tree)));
1877 /* Setup initial parameters */
1878 io.lockx.level = RAW_LOCK_LOCKX;
1879 io.lockx.in.timeout = 0;
1881 lock1.pid = cli->session->pid;
1882 lock1.offset = 0;
1883 lock1.count = 10;
1884 lock2.pid = cli->session->pid;
1885 lock2.offset = 10;
1886 lock2.count = 10;
1888 locks[0] = lock1;
1889 locks[1] = lock2;
1891 io.lockx.in.file.fnum = fnum1;
1892 io.lockx.in.mode = 0; /* exclusive */
1894 /** Test1: Take second lock, but not first. */
1895 torture_comment(tctx, " unlock 2 locks, first one not locked. Expect no locks "
1896 "unlocked. \n");
1898 io.lockx.in.ulock_cnt = 0;
1899 io.lockx.in.lock_cnt = 1;
1900 io.lockx.in.locks = &lock2;
1901 status = smb_raw_lock(cli->tree, &io);
1902 CHECK_STATUS(status, NT_STATUS_OK);
1904 /* Try to unlock both locks. */
1905 io.lockx.in.ulock_cnt = 2;
1906 io.lockx.in.lock_cnt = 0;
1907 io.lockx.in.locks = locks;
1909 status = smb_raw_lock(cli->tree, &io);
1910 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1912 /* Second lock should not be unlocked. */
1913 io.lockx.in.ulock_cnt = 0;
1914 io.lockx.in.lock_cnt = 1;
1915 io.lockx.in.locks = &lock2;
1916 status = smb_raw_lock(cli->tree, &io);
1917 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1919 /* cleanup */
1920 io.lockx.in.ulock_cnt = 1;
1921 io.lockx.in.lock_cnt = 0;
1922 io.lockx.in.locks = &lock2;
1923 status = smb_raw_lock(cli->tree, &io);
1924 CHECK_STATUS(status, NT_STATUS_OK);
1926 /** Test2: Take first lock, but not second. */
1927 torture_comment(tctx, " unlock 2 locks, second one not locked. Expect first lock "
1928 "unlocked.\n");
1930 io.lockx.in.ulock_cnt = 0;
1931 io.lockx.in.lock_cnt = 1;
1932 io.lockx.in.locks = &lock1;
1933 status = smb_raw_lock(cli->tree, &io);
1934 CHECK_STATUS(status, NT_STATUS_OK);
1936 /* Try to unlock both locks. */
1937 io.lockx.in.ulock_cnt = 2;
1938 io.lockx.in.lock_cnt = 0;
1939 io.lockx.in.locks = locks;
1941 status = smb_raw_lock(cli->tree, &io);
1942 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1944 /* First lock should be unlocked. */
1945 io.lockx.in.ulock_cnt = 0;
1946 io.lockx.in.lock_cnt = 1;
1947 io.lockx.in.locks = &lock1;
1948 status = smb_raw_lock(cli->tree, &io);
1949 CHECK_STATUS(status, NT_STATUS_OK);
1951 /* cleanup */
1952 io.lockx.in.ulock_cnt = 1;
1953 io.lockx.in.lock_cnt = 0;
1954 io.lockx.in.locks = &lock1;
1955 status = smb_raw_lock(cli->tree, &io);
1956 CHECK_STATUS(status, NT_STATUS_OK);
1958 /* Test3: Request 2 locks, second will contend. What happens to the
1959 * first? */
1960 torture_comment(tctx, " request 2 locks, second one will contend. "
1961 "Expect both to fail.\n");
1963 /* Lock the second range */
1964 io.lockx.in.ulock_cnt = 0;
1965 io.lockx.in.lock_cnt = 1;
1966 io.lockx.in.locks = &lock2;
1967 status = smb_raw_lock(cli->tree, &io);
1968 CHECK_STATUS(status, NT_STATUS_OK);
1970 /* Request both locks */
1971 io.lockx.in.ulock_cnt = 0;
1972 io.lockx.in.lock_cnt = 2;
1973 io.lockx.in.locks = locks;
1975 status = smb_raw_lock(cli->tree, &io);
1976 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1978 /* First lock should be unlocked. */
1979 io.lockx.in.ulock_cnt = 0;
1980 io.lockx.in.lock_cnt = 1;
1981 io.lockx.in.locks = &lock1;
1982 status = smb_raw_lock(cli->tree, &io);
1983 CHECK_STATUS(status, NT_STATUS_OK);
1985 /* cleanup */
1986 io.lockx.in.ulock_cnt = 2;
1987 io.lockx.in.lock_cnt = 0;
1988 io.lockx.in.locks = locks;
1989 status = smb_raw_lock(cli->tree, &io);
1990 CHECK_STATUS(status, NT_STATUS_OK);
1992 /* Test4: Request unlock and lock. The lock contends, is the unlock
1993 * then re-locked? */
1994 torture_comment(tctx, " request unlock and lock, second one will "
1995 "contend. Expect the unlock to succeed.\n");
1997 /* Lock both ranges */
1998 io.lockx.in.ulock_cnt = 0;
1999 io.lockx.in.lock_cnt = 2;
2000 io.lockx.in.locks = locks;
2001 status = smb_raw_lock(cli->tree, &io);
2002 CHECK_STATUS(status, NT_STATUS_OK);
2004 /* Attempt to unlock the first range and lock the second */
2005 io.lockx.in.ulock_cnt = 1;
2006 io.lockx.in.lock_cnt = 1;
2007 io.lockx.in.locks = locks;
2008 status = smb_raw_lock(cli->tree, &io);
2009 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2011 /* The first lock should've been unlocked */
2012 io.lockx.in.ulock_cnt = 0;
2013 io.lockx.in.lock_cnt = 1;
2014 io.lockx.in.locks = &lock1;
2015 status = smb_raw_lock(cli->tree, &io);
2016 CHECK_STATUS(status, NT_STATUS_OK);
2018 /* cleanup */
2019 io.lockx.in.ulock_cnt = 2;
2020 io.lockx.in.lock_cnt = 0;
2021 io.lockx.in.locks = locks;
2022 status = smb_raw_lock(cli->tree, &io);
2023 CHECK_STATUS(status, NT_STATUS_OK);
2025 done:
2026 smbcli_close(cli->tree, fnum1);
2027 smb_raw_exit(cli->session);
2028 smbcli_deltree(cli->tree, BASEDIR);
2029 return ret;
2033 * torture_locktest5 covers stacking pretty well, but its missing two tests:
2034 * - stacking an exclusive on top of shared fails
2035 * - stacking two exclusives fail
2037 static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
2039 union smb_lock io;
2040 NTSTATUS status;
2041 bool ret = true;
2042 int fnum1;
2043 const char *fname = BASEDIR "\\stacking.txt";
2044 struct smb_lock_entry lock1;
2046 torture_comment(tctx, "Testing stacking:\n");
2048 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2050 io.generic.level = RAW_LOCK_LOCKX;
2052 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2053 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2054 "Failed to create %s - %s\n",
2055 fname, smbcli_errstr(cli->tree)));
2057 /* Setup initial parameters */
2058 io.lockx.level = RAW_LOCK_LOCKX;
2059 io.lockx.in.timeout = 0;
2061 lock1.pid = cli->session->pid;
2062 lock1.offset = 0;
2063 lock1.count = 10;
2066 * Try to take a shared lock, then stack an exclusive.
2068 torture_comment(tctx, " stacking an exclusive on top of a shared lock fails.\n");
2069 io.lockx.in.file.fnum = fnum1;
2070 io.lockx.in.locks = &lock1;
2072 io.lockx.in.ulock_cnt = 0;
2073 io.lockx.in.lock_cnt = 1;
2074 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
2075 status = smb_raw_lock(cli->tree, &io);
2076 CHECK_STATUS(status, NT_STATUS_OK);
2078 io.lockx.in.ulock_cnt = 0;
2079 io.lockx.in.lock_cnt = 1;
2080 io.lockx.in.mode = 0;
2081 status = smb_raw_lock(cli->tree, &io);
2082 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2083 NT_STATUS_FILE_LOCK_CONFLICT);
2085 /* cleanup */
2086 io.lockx.in.ulock_cnt = 1;
2087 io.lockx.in.lock_cnt = 0;
2088 status = smb_raw_lock(cli->tree, &io);
2089 CHECK_STATUS(status, NT_STATUS_OK);
2092 * Prove that two exclusive locks do not stack.
2094 torture_comment(tctx, " two exclusive locks do not stack.\n");
2095 io.lockx.in.ulock_cnt = 0;
2096 io.lockx.in.lock_cnt = 1;
2097 io.lockx.in.mode = 0;
2098 status = smb_raw_lock(cli->tree, &io);
2099 CHECK_STATUS(status, NT_STATUS_OK);
2100 status = smb_raw_lock(cli->tree, &io);
2101 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2102 NT_STATUS_FILE_LOCK_CONFLICT);
2104 /* cleanup */
2105 io.lockx.in.ulock_cnt = 1;
2106 io.lockx.in.lock_cnt = 0;
2107 status = smb_raw_lock(cli->tree, &io);
2108 CHECK_STATUS(status, NT_STATUS_OK);
2110 done:
2111 smbcli_close(cli->tree, fnum1);
2112 smb_raw_exit(cli->session);
2113 smbcli_deltree(cli->tree, BASEDIR);
2114 return ret;
2118 * Test how 0-byte read requests contend with byte range locks
2120 static bool test_zerobyteread(struct torture_context *tctx,
2121 struct smbcli_state *cli)
2123 union smb_lock io;
2124 union smb_read rd;
2125 NTSTATUS status;
2126 bool ret = true;
2127 int fnum1, fnum2;
2128 const char *fname = BASEDIR "\\zerobyteread.txt";
2129 struct smb_lock_entry lock1;
2130 uint8_t c = 1;
2132 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2134 io.generic.level = RAW_LOCK_LOCKX;
2136 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2137 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2138 "Failed to create %s - %s\n",
2139 fname, smbcli_errstr(cli->tree)));
2141 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2142 torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
2143 "Failed to create %s - %s\n",
2144 fname, smbcli_errstr(cli->tree)));
2146 /* Setup initial parameters */
2147 io.lockx.level = RAW_LOCK_LOCKX;
2148 io.lockx.in.timeout = 0;
2150 lock1.pid = cli->session->pid;
2151 lock1.offset = 0;
2152 lock1.count = 10;
2154 ZERO_STRUCT(rd);
2155 rd.readx.level = RAW_READ_READX;
2157 torture_comment(tctx, "Testing zero byte read on lock range:\n");
2159 /* Take an exclusive lock */
2160 torture_comment(tctx, " taking exclusive lock.\n");
2161 io.lockx.in.ulock_cnt = 0;
2162 io.lockx.in.lock_cnt = 1;
2163 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2164 io.lockx.in.file.fnum = fnum1;
2165 io.lockx.in.locks = &lock1;
2166 status = smb_raw_lock(cli->tree, &io);
2167 CHECK_STATUS(status, NT_STATUS_OK);
2169 /* Try a zero byte read */
2170 torture_comment(tctx, " reading 0 bytes.\n");
2171 rd.readx.in.file.fnum = fnum2;
2172 rd.readx.in.offset = 5;
2173 rd.readx.in.mincnt = 0;
2174 rd.readx.in.maxcnt = 0;
2175 rd.readx.in.remaining = 0;
2176 rd.readx.in.read_for_execute = false;
2177 rd.readx.out.data = &c;
2178 status = smb_raw_read(cli->tree, &rd);
2179 torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2180 "zero byte read did not return 0 bytes");
2181 CHECK_STATUS(status, NT_STATUS_OK);
2183 /* Unlock lock */
2184 io.lockx.in.ulock_cnt = 1;
2185 io.lockx.in.lock_cnt = 0;
2186 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2187 io.lockx.in.file.fnum = fnum1;
2188 io.lockx.in.locks = &lock1;
2189 status = smb_raw_lock(cli->tree, &io);
2190 CHECK_STATUS(status, NT_STATUS_OK);
2192 torture_comment(tctx, "Testing zero byte read on zero byte lock "
2193 "range:\n");
2195 /* Take an exclusive lock */
2196 torture_comment(tctx, " taking exclusive 0-byte lock.\n");
2197 io.lockx.in.ulock_cnt = 0;
2198 io.lockx.in.lock_cnt = 1;
2199 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2200 io.lockx.in.file.fnum = fnum1;
2201 io.lockx.in.locks = &lock1;
2202 lock1.offset = 5;
2203 lock1.count = 0;
2204 status = smb_raw_lock(cli->tree, &io);
2205 CHECK_STATUS(status, NT_STATUS_OK);
2207 /* Try a zero byte read before the lock */
2208 torture_comment(tctx, " reading 0 bytes before the lock.\n");
2209 rd.readx.in.file.fnum = fnum2;
2210 rd.readx.in.offset = 4;
2211 rd.readx.in.mincnt = 0;
2212 rd.readx.in.maxcnt = 0;
2213 rd.readx.in.remaining = 0;
2214 rd.readx.in.read_for_execute = false;
2215 rd.readx.out.data = &c;
2216 status = smb_raw_read(cli->tree, &rd);
2217 torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2218 "zero byte read did not return 0 bytes");
2219 CHECK_STATUS(status, NT_STATUS_OK);
2221 /* Try a zero byte read on the lock */
2222 torture_comment(tctx, " reading 0 bytes on the lock.\n");
2223 rd.readx.in.file.fnum = fnum2;
2224 rd.readx.in.offset = 5;
2225 rd.readx.in.mincnt = 0;
2226 rd.readx.in.maxcnt = 0;
2227 rd.readx.in.remaining = 0;
2228 rd.readx.in.read_for_execute = false;
2229 rd.readx.out.data = &c;
2230 status = smb_raw_read(cli->tree, &rd);
2231 torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2232 "zero byte read did not return 0 bytes");
2233 CHECK_STATUS(status, NT_STATUS_OK);
2235 /* Try a zero byte read after the lock */
2236 torture_comment(tctx, " reading 0 bytes after the lock.\n");
2237 rd.readx.in.file.fnum = fnum2;
2238 rd.readx.in.offset = 6;
2239 rd.readx.in.mincnt = 0;
2240 rd.readx.in.maxcnt = 0;
2241 rd.readx.in.remaining = 0;
2242 rd.readx.in.read_for_execute = false;
2243 rd.readx.out.data = &c;
2244 status = smb_raw_read(cli->tree, &rd);
2245 torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2246 "zero byte read did not return 0 bytes");
2247 CHECK_STATUS(status, NT_STATUS_OK);
2249 /* Unlock lock */
2250 io.lockx.in.ulock_cnt = 1;
2251 io.lockx.in.lock_cnt = 0;
2252 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2253 io.lockx.in.file.fnum = fnum1;
2254 io.lockx.in.locks = &lock1;
2255 status = smb_raw_lock(cli->tree, &io);
2256 CHECK_STATUS(status, NT_STATUS_OK);
2258 done:
2259 smbcli_close(cli->tree, fnum1);
2260 smbcli_close(cli->tree, fnum2);
2261 smb_raw_exit(cli->session);
2262 smbcli_deltree(cli->tree, BASEDIR);
2263 return ret;
2266 test multi Locking&X operation
2268 static bool test_multilock(struct torture_context *tctx,
2269 struct smbcli_state *cli)
2271 union smb_lock io;
2272 struct smb_lock_entry lock[2];
2273 NTSTATUS status;
2274 bool ret = true;
2275 int fnum;
2276 const char *fname = BASEDIR "\\multilock_test.txt";
2277 time_t t;
2278 struct smbcli_request *req;
2279 struct smbcli_session_options options;
2281 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2283 lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
2285 torture_comment(tctx, "Testing LOCKING_ANDX multi-lock\n");
2286 io.generic.level = RAW_LOCK_LOCKX;
2288 /* Create the test file. */
2289 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2290 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
2291 "Failed to create %s - %s\n",
2292 fname, smbcli_errstr(cli->tree)));
2295 * Lock regions 100->109, 120->129 as
2296 * two separate write locks in one request.
2298 io.lockx.level = RAW_LOCK_LOCKX;
2299 io.lockx.in.file.fnum = fnum;
2300 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2301 io.lockx.in.timeout = 0;
2302 io.lockx.in.ulock_cnt = 0;
2303 io.lockx.in.lock_cnt = 2;
2304 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2305 lock[0].pid = cli->session->pid;
2306 lock[0].offset = 100;
2307 lock[0].count = 10;
2308 lock[1].pid = cli->session->pid;
2309 lock[1].offset = 120;
2310 lock[1].count = 10;
2311 io.lockx.in.locks = &lock[0];
2312 status = smb_raw_lock(cli->tree, &io);
2313 CHECK_STATUS(status, NT_STATUS_OK);
2316 * Now request the same locks on a different
2317 * context as blocking locks with infinite timeout.
2320 io.lockx.in.timeout = 20000;
2321 lock[0].pid = cli->session->pid+1;
2322 lock[1].pid = cli->session->pid+1;
2323 req = smb_raw_lock_send(cli->tree, &io);
2324 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2325 "Failed to setup timed locks (%s)\n", __location__));
2327 /* Unlock lock[0] */
2328 io.lockx.in.timeout = 0;
2329 io.lockx.in.ulock_cnt = 1;
2330 io.lockx.in.lock_cnt = 0;
2331 io.lockx.in.locks = &lock[0];
2332 lock[0].pid = cli->session->pid;
2333 status = smb_raw_lock(cli->tree, &io);
2334 CHECK_STATUS(status, NT_STATUS_OK);
2336 /* Start the clock. */
2337 t = time_mono(NULL);
2339 /* Unlock lock[1] */
2340 io.lockx.in.timeout = 0;
2341 io.lockx.in.ulock_cnt = 1;
2342 io.lockx.in.lock_cnt = 0;
2343 io.lockx.in.locks = &lock[1];
2344 lock[1].pid = cli->session->pid;
2345 status = smb_raw_lock(cli->tree, &io);
2346 CHECK_STATUS(status, NT_STATUS_OK);
2348 /* receive the successful blocked lock requests */
2349 status = smbcli_request_simple_recv(req);
2350 CHECK_STATUS(status, NT_STATUS_OK);
2352 /* Fail if this took more than 2 seconds. */
2353 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
2354 "Blocking locks were not granted immediately (%s)\n",
2355 __location__));
2356 done:
2357 smb_raw_exit(cli->session);
2358 smbcli_deltree(cli->tree, BASEDIR);
2359 return ret;
2363 test multi2 Locking&X operation
2364 This test is designed to show that
2365 lock precedence on the server is based
2366 on the order received, not on the ability
2367 to grant. For example:
2369 A blocked lock request containing 2 locks
2370 will be satisfied before a subsequent blocked
2371 lock request over one of the same regions,
2372 even if that region is then unlocked. E.g.
2374 (a) lock 100->109, 120->129 (granted)
2375 (b) lock 100->109, 120-129 (blocks)
2376 (c) lock 100->109 (blocks)
2377 (d) unlock 100->109
2379 lock (c) will not be granted as lock (b)
2380 will take precedence.
2382 static bool test_multilock2(struct torture_context *tctx,
2383 struct smbcli_state *cli)
2385 union smb_lock io;
2386 struct smb_lock_entry lock[2];
2387 NTSTATUS status;
2388 bool ret = true;
2389 int fnum;
2390 const char *fname = BASEDIR "\\multilock2_test.txt";
2391 time_t t;
2392 struct smbcli_request *req;
2393 struct smbcli_request *req2;
2394 struct smbcli_session_options options;
2396 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2398 lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
2400 torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 2\n");
2401 io.generic.level = RAW_LOCK_LOCKX;
2403 /* Create the test file. */
2404 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2405 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
2406 "Failed to create %s - %s\n",
2407 fname, smbcli_errstr(cli->tree)));
2410 * Lock regions 100->109, 120->129 as
2411 * two separate write locks in one request.
2413 io.lockx.level = RAW_LOCK_LOCKX;
2414 io.lockx.in.file.fnum = fnum;
2415 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2416 io.lockx.in.timeout = 0;
2417 io.lockx.in.ulock_cnt = 0;
2418 io.lockx.in.lock_cnt = 2;
2419 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2420 lock[0].pid = cli->session->pid;
2421 lock[0].offset = 100;
2422 lock[0].count = 10;
2423 lock[1].pid = cli->session->pid;
2424 lock[1].offset = 120;
2425 lock[1].count = 10;
2426 io.lockx.in.locks = &lock[0];
2427 status = smb_raw_lock(cli->tree, &io);
2428 CHECK_STATUS(status, NT_STATUS_OK);
2431 * Now request the same locks on a different
2432 * context as blocking locks.
2435 io.lockx.in.timeout = 20000;
2436 lock[0].pid = cli->session->pid+1;
2437 lock[1].pid = cli->session->pid+1;
2438 req = smb_raw_lock_send(cli->tree, &io);
2439 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2440 "Failed to setup timed locks (%s)\n", __location__));
2443 * Request the first lock again on a separate context.
2444 * Wait 2 seconds. This should time out (the previous
2445 * multi-lock request should take precedence).
2448 io.lockx.in.timeout = 2000;
2449 lock[0].pid = cli->session->pid+2;
2450 io.lockx.in.lock_cnt = 1;
2451 req2 = smb_raw_lock_send(cli->tree, &io);
2452 torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
2453 "Failed to setup timed locks (%s)\n", __location__));
2455 /* Unlock lock[0] */
2456 io.lockx.in.timeout = 0;
2457 io.lockx.in.ulock_cnt = 1;
2458 io.lockx.in.lock_cnt = 0;
2459 io.lockx.in.locks = &lock[0];
2460 lock[0].pid = cli->session->pid;
2461 status = smb_raw_lock(cli->tree, &io);
2462 CHECK_STATUS(status, NT_STATUS_OK);
2464 /* Did the second lock complete (should time out) ? */
2465 status = smbcli_request_simple_recv(req2);
2466 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2468 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2469 "req should still wait");
2471 /* Start the clock. */
2472 t = time_mono(NULL);
2474 /* Unlock lock[1] */
2475 io.lockx.in.timeout = 0;
2476 io.lockx.in.ulock_cnt = 1;
2477 io.lockx.in.lock_cnt = 0;
2478 io.lockx.in.locks = &lock[1];
2479 lock[1].pid = cli->session->pid;
2480 status = smb_raw_lock(cli->tree, &io);
2481 CHECK_STATUS(status, NT_STATUS_OK);
2483 /* receive the successful blocked lock requests */
2484 status = smbcli_request_simple_recv(req);
2485 CHECK_STATUS(status, NT_STATUS_OK);
2487 /* Fail if this took more than 2 seconds. */
2488 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
2489 "Blocking locks were not granted immediately (%s)\n",
2490 __location__));
2491 done:
2492 smb_raw_exit(cli->session);
2493 smbcli_deltree(cli->tree, BASEDIR);
2494 return ret;
2498 test multi3 Locking&X operation
2499 This test is designed to show that
2500 lock precedence on the server is based
2501 on the order received, not on the ability
2502 to grant.
2504 Compared to test_multilock2() (above)
2505 this test demonstrates that completely
2506 unrelated ranges work independently.
2508 For example:
2510 A blocked lock request containing 2 locks
2511 will be satisfied before a subsequent blocked
2512 lock request over one of the same regions,
2513 even if that region is then unlocked. But
2514 a lock of a different region goes through. E.g.
2516 All locks are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
2518 (a) lock 100->109, 120->129 (granted)
2519 (b) lock 100->109, 120->129 (blocks, timeout=20s)
2520 (c) lock 100->109 (blocks, timeout=2s)
2521 (d) lock 110->119 (granted)
2522 (e) lock 110->119 (blocks, timeout=20s)
2523 (f) unlock 100->109 (a)
2524 (g) lock 100->109 (not granted, blocked by (b))
2525 (h) lock 100->109 (not granted, blocked by itself (b))
2526 (i) lock (c) will not be granted(conflict, times out)
2527 as lock (b) will take precedence.
2528 (j) unlock 110-119 (d)
2529 (k) lock (e) completes and is not blocked by (a) nor (b)
2530 (l) lock 100->109 (not granted(conflict), blocked by (b))
2531 (m) lock 100->109 (not granted(conflict), blocked by itself (b))
2532 (n) unlock 120-129 (a)
2533 (o) lock (b) completes
2535 static bool test_multilock3(struct torture_context *tctx,
2536 struct smbcli_state *cli)
2538 union smb_lock io;
2539 struct smb_lock_entry lock[2];
2540 union smb_lock io3;
2541 struct smb_lock_entry lock3[1];
2542 NTSTATUS status;
2543 bool ret = true;
2544 int fnum;
2545 const char *fname = BASEDIR "\\multilock3_test.txt";
2546 time_t t;
2547 struct smbcli_request *req = NULL;
2548 struct smbcli_request *req2 = NULL;
2549 struct smbcli_request *req4 = NULL;
2551 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
2552 "Failed to setup up test directory: " BASEDIR);
2554 torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 3\n");
2555 io.generic.level = RAW_LOCK_LOCKX;
2557 /* Create the test file. */
2558 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2559 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
2560 "Failed to create %s - %s\n",
2561 fname, smbcli_errstr(cli->tree)));
2564 * a)
2565 * Lock regions 100->109, 120->129 as
2566 * two separate write locks in one request.
2568 io.lockx.level = RAW_LOCK_LOCKX;
2569 io.lockx.in.file.fnum = fnum;
2570 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2571 io.lockx.in.timeout = 0;
2572 io.lockx.in.ulock_cnt = 0;
2573 io.lockx.in.lock_cnt = 2;
2574 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2575 lock[0].pid = cli->session->pid;
2576 lock[0].offset = 100;
2577 lock[0].count = 10;
2578 lock[1].pid = cli->session->pid;
2579 lock[1].offset = 120;
2580 lock[1].count = 10;
2581 io.lockx.in.locks = &lock[0];
2582 status = smb_raw_lock(cli->tree, &io);
2583 CHECK_STATUS(status, NT_STATUS_OK);
2586 * b)
2587 * Now request the same locks on a different
2588 * context as blocking locks.
2590 io.lockx.in.timeout = 20000;
2591 lock[0].pid = cli->session->pid+1;
2592 lock[1].pid = cli->session->pid+1;
2593 req = smb_raw_lock_send(cli->tree, &io);
2594 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2595 "Failed to setup timed locks (%s)\n", __location__));
2598 * c)
2599 * Request the first lock again on a separate context.
2600 * Wait 2 seconds. This should time out (the previous
2601 * multi-lock request should take precedence).
2603 io.lockx.in.timeout = 2000;
2604 lock[0].pid = cli->session->pid+2;
2605 io.lockx.in.lock_cnt = 1;
2606 req2 = smb_raw_lock_send(cli->tree, &io);
2607 torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
2608 "Failed to setup timed locks (%s)\n", __location__));
2611 * d)
2612 * Lock regions 110->119
2614 io3.lockx.level = RAW_LOCK_LOCKX;
2615 io3.lockx.in.file.fnum = fnum;
2616 io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2617 io3.lockx.in.timeout = 0;
2618 io3.lockx.in.ulock_cnt = 0;
2619 io3.lockx.in.lock_cnt = 1;
2620 io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2621 lock3[0].pid = cli->session->pid+3;
2622 lock3[0].offset = 110;
2623 lock3[0].count = 10;
2624 io3.lockx.in.locks = &lock3[0];
2625 status = smb_raw_lock(cli->tree, &io3);
2626 CHECK_STATUS(status, NT_STATUS_OK);
2629 * e)
2630 * try 110-119 again
2632 io3.lockx.in.timeout = 20000;
2633 lock3[0].pid = cli->session->pid+4;
2634 req4 = smb_raw_lock_send(cli->tree, &io3);
2635 torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
2636 "Failed to setup timed locks (%s)\n", __location__));
2639 * f)
2640 * Unlock (a) lock[0] 100-109
2642 io.lockx.in.timeout = 0;
2643 io.lockx.in.ulock_cnt = 1;
2644 io.lockx.in.lock_cnt = 0;
2645 io.lockx.in.locks = &lock[0];
2646 lock[0].pid = cli->session->pid;
2647 status = smb_raw_lock(cli->tree, &io);
2648 CHECK_STATUS(status, NT_STATUS_OK);
2651 * g)
2652 * try to lock lock[0] 100-109 again
2654 lock[0].pid = cli->session->pid+5;
2655 io.lockx.in.ulock_cnt = 0;
2656 io.lockx.in.lock_cnt = 1;
2657 status = smb_raw_lock(cli->tree, &io);
2658 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2661 * h)
2662 * try to lock lock[0] 100-109 again with
2663 * the pid that's still waiting
2665 lock[0].pid = cli->session->pid+1;
2666 io.lockx.in.ulock_cnt = 0;
2667 io.lockx.in.lock_cnt = 1;
2668 status = smb_raw_lock(cli->tree, &io);
2669 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2671 torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
2672 "req2 should still wait");
2675 * i)
2676 * Did the second lock complete (should time out) ?
2678 status = smbcli_request_simple_recv(req2);
2679 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2681 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2682 "req should still wait");
2683 torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
2684 "req4 should still wait");
2687 * j)
2688 * Unlock (d) lock[0] 110-119
2690 io3.lockx.in.timeout = 0;
2691 io3.lockx.in.ulock_cnt = 1;
2692 io3.lockx.in.lock_cnt = 0;
2693 lock3[0].pid = cli->session->pid+3;
2694 status = smb_raw_lock(cli->tree, &io3);
2695 CHECK_STATUS(status, NT_STATUS_OK);
2698 * k)
2699 * receive the successful blocked lock request (e)
2700 * on 110-119 while the 100-109/120-129 is still waiting.
2702 status = smbcli_request_simple_recv(req4);
2703 CHECK_STATUS(status, NT_STATUS_OK);
2706 * l)
2707 * try to lock lock[0] 100-109 again
2709 lock[0].pid = cli->session->pid+6;
2710 io.lockx.in.ulock_cnt = 0;
2711 io.lockx.in.lock_cnt = 1;
2712 status = smb_raw_lock(cli->tree, &io);
2713 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2715 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2716 "req should still wait");
2719 * m)
2720 * try to lock lock[0] 100-109 again with
2721 * the pid that's still waiting
2723 lock[0].pid = cli->session->pid+1;
2724 io.lockx.in.ulock_cnt = 0;
2725 io.lockx.in.lock_cnt = 1;
2726 status = smb_raw_lock(cli->tree, &io);
2727 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2729 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2730 "req should still wait");
2732 /* Start the clock. */
2733 t = time_mono(NULL);
2736 * n)
2737 * Unlock lock[1] 120-129 */
2738 io.lockx.in.timeout = 0;
2739 io.lockx.in.ulock_cnt = 1;
2740 io.lockx.in.lock_cnt = 0;
2741 io.lockx.in.locks = &lock[1];
2742 lock[1].pid = cli->session->pid;
2743 status = smb_raw_lock(cli->tree, &io);
2744 CHECK_STATUS(status, NT_STATUS_OK);
2747 * o)
2748 * receive the successful blocked lock request (b)
2750 status = smbcli_request_simple_recv(req);
2751 CHECK_STATUS(status, NT_STATUS_OK);
2753 /* Fail if this took more than 2 seconds. */
2754 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
2755 "Blocking locks were not granted immediately (%s)\n",
2756 __location__));
2757 done:
2758 smb_raw_exit(cli->session);
2759 smbcli_deltree(cli->tree, BASEDIR);
2760 return ret;
2764 test multi4 Locking&X operation
2765 This test is designed to show that
2766 lock precedence on the server is based
2767 on the order received, not on the ability
2768 to grant.
2770 Compared to test_multilock3() (above)
2771 this test demonstrates that pending read-only/shared
2772 locks doesn't block shared locks others.
2774 The outstanding requests build an implicit
2775 database that's checked before checking
2776 the already granted locks in the real database.
2778 For example:
2780 A blocked read-lock request containing 2 locks
2781 will be still be blocked, while one region
2782 is still write-locked. While it doesn't block
2783 other read-lock requests for the other region. E.g.
2785 (a) lock(rw) 100->109, 120->129 (granted)
2786 (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s)
2787 (c) lock(ro) 100->109 (blocks, timeout=MAX)
2788 (d) lock(rw) 110->119 (granted)
2789 (e) lock(rw) 110->119 (blocks, timeout=20s)
2790 (f) unlock 100->109 (a)
2791 (g) lock(ro) (c) completes and is not blocked by (a) nor (b)
2792 (h) lock(rw) 100->109 (not granted, blocked by (c))
2793 (i) lock(rw) 100->109 (pid (b)) (not granted(conflict), blocked by (c))
2794 (j) unlock 110-119
2795 (k) lock (e) completes and is not blocked by (a) nor (b)
2796 (l) lock 100->109 (not granted(conflict), blocked by (b))
2797 (m) lock 100->109 (pid (b)) (not granted(conflict), blocked by itself (b))
2798 (n) unlock 120-129 (a)
2799 (o) lock (b) completes
2801 static bool test_multilock4(struct torture_context *tctx,
2802 struct smbcli_state *cli)
2804 union smb_lock io;
2805 struct smb_lock_entry lock[2];
2806 union smb_lock io3;
2807 struct smb_lock_entry lock3[1];
2808 NTSTATUS status;
2809 bool ret = true;
2810 int fnum;
2811 const char *fname = BASEDIR "\\multilock4_test.txt";
2812 time_t t;
2813 struct smbcli_request *req = NULL;
2814 struct smbcli_request *req2 = NULL;
2815 struct smbcli_request *req4 = NULL;
2817 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
2818 "Failed to setup up test directory: " BASEDIR);
2820 torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 4\n");
2821 io.generic.level = RAW_LOCK_LOCKX;
2823 /* Create the test file. */
2824 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2825 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
2826 "Failed to create %s - %s\n",
2827 fname, smbcli_errstr(cli->tree)));
2830 * a)
2831 * Lock regions 100->109, 120->129 as
2832 * two separate write locks in one request.
2834 io.lockx.level = RAW_LOCK_LOCKX;
2835 io.lockx.in.file.fnum = fnum;
2836 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2837 io.lockx.in.timeout = 0;
2838 io.lockx.in.ulock_cnt = 0;
2839 io.lockx.in.lock_cnt = 2;
2840 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2841 lock[0].pid = cli->session->pid;
2842 lock[0].offset = 100;
2843 lock[0].count = 10;
2844 lock[1].pid = cli->session->pid;
2845 lock[1].offset = 120;
2846 lock[1].count = 10;
2847 io.lockx.in.locks = &lock[0];
2848 status = smb_raw_lock(cli->tree, &io);
2849 CHECK_STATUS(status, NT_STATUS_OK);
2852 * b)
2853 * Now request the same locks on a different
2854 * context as blocking locks. But readonly.
2856 io.lockx.in.timeout = 20000;
2857 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
2858 lock[0].pid = cli->session->pid+1;
2859 lock[1].pid = cli->session->pid+1;
2860 req = smb_raw_lock_send(cli->tree, &io);
2861 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2862 "Failed to setup timed locks (%s)\n", __location__));
2865 * c)
2866 * Request the first lock again on a separate context.
2867 * Wait forever. The previous multi-lock request (b)
2868 * should take precedence. Also readonly.
2870 io.lockx.in.timeout = UINT32_MAX;
2871 lock[0].pid = cli->session->pid+2;
2872 io.lockx.in.lock_cnt = 1;
2873 req2 = smb_raw_lock_send(cli->tree, &io);
2874 torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
2875 "Failed to setup timed locks (%s)\n", __location__));
2878 * d)
2879 * Lock regions 110->119
2881 io3.lockx.level = RAW_LOCK_LOCKX;
2882 io3.lockx.in.file.fnum = fnum;
2883 io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2884 io3.lockx.in.timeout = 0;
2885 io3.lockx.in.ulock_cnt = 0;
2886 io3.lockx.in.lock_cnt = 1;
2887 io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2888 lock3[0].pid = cli->session->pid+3;
2889 lock3[0].offset = 110;
2890 lock3[0].count = 10;
2891 io3.lockx.in.locks = &lock3[0];
2892 status = smb_raw_lock(cli->tree, &io3);
2893 CHECK_STATUS(status, NT_STATUS_OK);
2896 * e)
2897 * try 110-119 again
2899 io3.lockx.in.timeout = 20000;
2900 lock3[0].pid = cli->session->pid+4;
2901 req4 = smb_raw_lock_send(cli->tree, &io3);
2902 torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
2903 "Failed to setup timed locks (%s)\n", __location__));
2906 * f)
2907 * Unlock (a) lock[0] 100-109
2909 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2910 io.lockx.in.timeout = 0;
2911 io.lockx.in.ulock_cnt = 1;
2912 io.lockx.in.lock_cnt = 0;
2913 io.lockx.in.locks = &lock[0];
2914 lock[0].pid = cli->session->pid;
2915 status = smb_raw_lock(cli->tree, &io);
2916 CHECK_STATUS(status, NT_STATUS_OK);
2919 * g)
2920 * receive the successful blocked lock request (c)
2921 * on 110-119 while (b) 100-109/120-129 is still waiting.
2923 status = smbcli_request_simple_recv(req2);
2924 CHECK_STATUS(status, NT_STATUS_OK);
2927 * h)
2928 * try to lock lock[0] 100-109 again
2929 * (read/write)
2931 lock[0].pid = cli->session->pid+5;
2932 io.lockx.in.ulock_cnt = 0;
2933 io.lockx.in.lock_cnt = 1;
2934 status = smb_raw_lock(cli->tree, &io);
2935 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2938 * i)
2939 * try to lock lock[0] 100-109 again with the pid (b)
2940 * that's still waiting.
2942 lock[0].pid = cli->session->pid+1;
2943 io.lockx.in.ulock_cnt = 0;
2944 io.lockx.in.lock_cnt = 1;
2945 status = smb_raw_lock(cli->tree, &io);
2946 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2948 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2949 "req should still wait");
2950 torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
2951 "req4 should still wait");
2954 * j)
2955 * Unlock (d) lock[0] 110-119
2957 io3.lockx.in.timeout = 0;
2958 io3.lockx.in.ulock_cnt = 1;
2959 io3.lockx.in.lock_cnt = 0;
2960 lock3[0].pid = cli->session->pid+3;
2961 status = smb_raw_lock(cli->tree, &io3);
2962 CHECK_STATUS(status, NT_STATUS_OK);
2965 * k)
2966 * receive the successful blocked
2967 * lock request (e) on 110-119.
2969 status = smbcli_request_simple_recv(req4);
2970 CHECK_STATUS(status, NT_STATUS_OK);
2973 * l)
2974 * try to lock lock[0] 100-109 again
2976 lock[0].pid = cli->session->pid+6;
2977 io.lockx.in.ulock_cnt = 0;
2978 io.lockx.in.lock_cnt = 1;
2979 status = smb_raw_lock(cli->tree, &io);
2980 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2983 * m)
2984 * try to lock lock[0] 100-109 again with the pid (b)
2985 * that's still waiting
2987 lock[0].pid = cli->session->pid+1;
2988 io.lockx.in.ulock_cnt = 0;
2989 io.lockx.in.lock_cnt = 1;
2990 status = smb_raw_lock(cli->tree, &io);
2991 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2993 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2994 "req should still wait");
2996 /* Start the clock. */
2997 t = time_mono(NULL);
3000 * n)
3001 * Unlock (a) lock[1] 120-129
3003 io.lockx.in.timeout = 0;
3004 io.lockx.in.ulock_cnt = 1;
3005 io.lockx.in.lock_cnt = 0;
3006 io.lockx.in.locks = &lock[1];
3007 lock[1].pid = cli->session->pid;
3008 status = smb_raw_lock(cli->tree, &io);
3009 CHECK_STATUS(status, NT_STATUS_OK);
3012 * o)
3013 * receive the successful blocked lock request (b)
3015 status = smbcli_request_simple_recv(req);
3016 CHECK_STATUS(status, NT_STATUS_OK);
3018 /* Fail if this took more than 2 seconds. */
3019 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
3020 "Blocking locks were not granted immediately (%s)\n",
3021 __location__));
3022 done:
3023 smb_raw_exit(cli->session);
3024 smbcli_deltree(cli->tree, BASEDIR);
3025 return ret;
3029 test multi5 Locking&X operation
3030 This test is designed to show that
3031 lock precedence on the server is based
3032 on the order received, not on the ability
3033 to grant.
3035 Compared to test_multilock3() (above)
3036 this test demonstrates that the initial
3037 lock request that block the following
3038 exclusive locks can be a shared lock.
3040 For example:
3042 All locks except (a) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
3044 (a) lock(ro) 100->109, 120->129 (granted)
3045 (b) lock 100->109, 120->129 (blocks, timeout=20s)
3046 (c) lock 100->109 (blocks, timeout=2s)
3047 (d) lock 110->119 (granted)
3048 (e) lock 110->119 (blocks, timeout=20s)
3049 (f) unlock 100->109 (a)
3050 (g) lock 100->109 (not granted, blocked by (b))
3051 (h) lock 100->109 (not granted, blocked by itself (b))
3052 (i) lock (c) will not be granted(conflict, times out)
3053 as lock (b) will take precedence.
3054 (j) unlock 110-119 (d)
3055 (k) lock (e) completes and is not blocked by (a) nor (b)
3056 (l) lock 100->109 (not granted(conflict), blocked by (b))
3057 (m) lock 100->109 (not granted(conflict), blocked by itself (b))
3058 (n) unlock 120-129 (a)
3059 (o) lock (b) completes
3061 static bool test_multilock5(struct torture_context *tctx,
3062 struct smbcli_state *cli)
3064 union smb_lock io;
3065 struct smb_lock_entry lock[2];
3066 union smb_lock io3;
3067 struct smb_lock_entry lock3[1];
3068 NTSTATUS status;
3069 bool ret = true;
3070 int fnum;
3071 const char *fname = BASEDIR "\\multilock5_test.txt";
3072 time_t t;
3073 struct smbcli_request *req = NULL;
3074 struct smbcli_request *req2 = NULL;
3075 struct smbcli_request *req4 = NULL;
3077 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
3078 "Failed to setup up test directory: " BASEDIR);
3080 torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 5\n");
3081 io.generic.level = RAW_LOCK_LOCKX;
3083 /* Create the test file. */
3084 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3085 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
3086 "Failed to create %s - %s\n",
3087 fname, smbcli_errstr(cli->tree)));
3090 * a)
3091 * Lock regions 100->109, 120->129 as
3092 * two separate write locks in one request.
3093 * (read only)
3095 io.lockx.level = RAW_LOCK_LOCKX;
3096 io.lockx.in.file.fnum = fnum;
3097 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3098 io.lockx.in.timeout = 0;
3099 io.lockx.in.ulock_cnt = 0;
3100 io.lockx.in.lock_cnt = 2;
3101 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
3102 lock[0].pid = cli->session->pid;
3103 lock[0].offset = 100;
3104 lock[0].count = 10;
3105 lock[1].pid = cli->session->pid;
3106 lock[1].offset = 120;
3107 lock[1].count = 10;
3108 io.lockx.in.locks = &lock[0];
3109 status = smb_raw_lock(cli->tree, &io);
3110 CHECK_STATUS(status, NT_STATUS_OK);
3113 * b)
3114 * Now request the same locks on a different
3115 * context as blocking locks.
3116 * (read write)
3118 io.lockx.in.timeout = 20000;
3119 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3120 lock[0].pid = cli->session->pid+1;
3121 lock[1].pid = cli->session->pid+1;
3122 req = smb_raw_lock_send(cli->tree, &io);
3123 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
3124 "Failed to setup timed locks (%s)\n", __location__));
3127 * c)
3128 * Request the first lock again on a separate context.
3129 * Wait 2 seconds. This should time out (the previous
3130 * multi-lock request should take precedence).
3131 * (read write)
3133 io.lockx.in.timeout = 2000;
3134 lock[0].pid = cli->session->pid+2;
3135 io.lockx.in.lock_cnt = 1;
3136 req2 = smb_raw_lock_send(cli->tree, &io);
3137 torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
3138 "Failed to setup timed locks (%s)\n", __location__));
3141 * d)
3142 * Lock regions 110->119
3144 io3.lockx.level = RAW_LOCK_LOCKX;
3145 io3.lockx.in.file.fnum = fnum;
3146 io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3147 io3.lockx.in.timeout = 0;
3148 io3.lockx.in.ulock_cnt = 0;
3149 io3.lockx.in.lock_cnt = 1;
3150 io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3151 lock3[0].pid = cli->session->pid+3;
3152 lock3[0].offset = 110;
3153 lock3[0].count = 10;
3154 io3.lockx.in.locks = &lock3[0];
3155 status = smb_raw_lock(cli->tree, &io3);
3156 CHECK_STATUS(status, NT_STATUS_OK);
3159 * e)
3160 * try 110-119 again
3162 io3.lockx.in.timeout = 20000;
3163 lock3[0].pid = cli->session->pid+4;
3164 req4 = smb_raw_lock_send(cli->tree, &io3);
3165 torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
3166 "Failed to setup timed locks (%s)\n", __location__));
3169 * f)
3170 * Unlock (a) lock[0] 100-109
3172 * Note we send LOCKING_ANDX_EXCLUSIVE_LOCK
3173 * while the lock used LOCKING_ANDX_SHARED_LOCK
3174 * to check if that also works.
3176 io.lockx.in.timeout = 0;
3177 io.lockx.in.ulock_cnt = 1;
3178 io.lockx.in.lock_cnt = 0;
3179 io.lockx.in.locks = &lock[0];
3180 lock[0].pid = cli->session->pid;
3181 status = smb_raw_lock(cli->tree, &io);
3182 CHECK_STATUS(status, NT_STATUS_OK);
3185 * g)
3186 * try to lock lock[0] 100-109 again
3188 lock[0].pid = cli->session->pid+5;
3189 io.lockx.in.ulock_cnt = 0;
3190 io.lockx.in.lock_cnt = 1;
3191 status = smb_raw_lock(cli->tree, &io);
3192 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3195 * h)
3196 * try to lock lock[0] 100-109 again with the pid (b)
3197 * that's still waiting.
3198 * (read write)
3200 lock[0].pid = cli->session->pid+1;
3201 io.lockx.in.ulock_cnt = 0;
3202 io.lockx.in.lock_cnt = 1;
3203 status = smb_raw_lock(cli->tree, &io);
3204 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3206 torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
3207 "req2 should still wait");
3210 * i)
3211 * Did the second lock complete (should time out) ?
3213 status = smbcli_request_simple_recv(req2);
3214 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3216 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3217 "req should still wait");
3218 torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
3219 "req4 should still wait");
3222 * j)
3223 * Unlock (d) lock[0] 110-119
3225 io3.lockx.in.timeout = 0;
3226 io3.lockx.in.ulock_cnt = 1;
3227 io3.lockx.in.lock_cnt = 0;
3228 lock3[0].pid = cli->session->pid+3;
3229 status = smb_raw_lock(cli->tree, &io3);
3230 CHECK_STATUS(status, NT_STATUS_OK);
3233 * k)
3234 * receive the successful blocked lock requests
3235 * on 110-119 while the 100-109/120-129 is still waiting.
3237 status = smbcli_request_simple_recv(req4);
3238 CHECK_STATUS(status, NT_STATUS_OK);
3241 * l)
3242 * try to lock lock[0] 100-109 again
3244 lock[0].pid = cli->session->pid+6;
3245 io.lockx.in.ulock_cnt = 0;
3246 io.lockx.in.lock_cnt = 1;
3247 status = smb_raw_lock(cli->tree, &io);
3248 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3251 * m)
3252 * try to lock lock[0] 100-109 again with the pid (b)
3253 * that's still waiting
3255 lock[0].pid = cli->session->pid+1;
3256 io.lockx.in.ulock_cnt = 0;
3257 io.lockx.in.lock_cnt = 1;
3258 status = smb_raw_lock(cli->tree, &io);
3259 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3261 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3262 "req should still wait");
3264 /* Start the clock. */
3265 t = time_mono(NULL);
3268 * n)
3269 * Unlock (a) lock[1] 120-129
3271 io.lockx.in.timeout = 0;
3272 io.lockx.in.ulock_cnt = 1;
3273 io.lockx.in.lock_cnt = 0;
3274 io.lockx.in.locks = &lock[1];
3275 lock[1].pid = cli->session->pid;
3276 status = smb_raw_lock(cli->tree, &io);
3277 CHECK_STATUS(status, NT_STATUS_OK);
3280 * o)
3281 * receive the successful blocked lock request (b)
3283 status = smbcli_request_simple_recv(req);
3284 CHECK_STATUS(status, NT_STATUS_OK);
3286 /* Fail if this took more than 2 seconds. */
3287 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
3288 "Blocking locks were not granted immediately (%s)\n",
3289 __location__));
3290 done:
3291 smb_raw_exit(cli->session);
3292 smbcli_deltree(cli->tree, BASEDIR);
3293 return ret;
3297 test multi6 Locking&X operation
3298 This test is designed to show that
3299 lock precedence on the server is based
3300 on the order received, not on the ability
3301 to grant.
3303 Compared to test_multilock4() (above)
3304 this test demonstrates the behavior if
3305 only just the first blocking lock
3306 being a shared lock.
3308 For example:
3310 All locks except (b) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
3312 (a) lock 100->109, 120->129 (granted)
3313 (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s)
3314 (c) lock 100->109 (blocks, timeout=2s)
3315 (d) lock 110->119 (granted)
3316 (e) lock 110->119 (blocks, timeout=20s)
3317 (f) unlock 100->109 (a)
3318 (g) lock 100->109 (not granted, blocked by (b))
3319 (h) lock 100->109 (not granted, blocked by itself (b))
3320 (i) lock (c) will not be granted(conflict, times out)
3321 as lock (b) will take precedence.
3322 (j) unlock 110-119 (d)
3323 (k) lock (e) completes and is not blocked by (a) nor (b)
3324 (l) lock 100->109 (not granted(conflict), blocked by (b))
3325 (m) lock 100->109 (not granted(conflict), blocked by itself (b))
3326 (n) unlock 120-129 (a)
3327 (o) lock (b) completes
3329 static bool test_multilock6(struct torture_context *tctx,
3330 struct smbcli_state *cli)
3332 union smb_lock io;
3333 struct smb_lock_entry lock[2];
3334 union smb_lock io3;
3335 struct smb_lock_entry lock3[1];
3336 NTSTATUS status;
3337 bool ret = true;
3338 int fnum;
3339 const char *fname = BASEDIR "\\multilock6_test.txt";
3340 time_t t;
3341 struct smbcli_request *req = NULL;
3342 struct smbcli_request *req2 = NULL;
3343 struct smbcli_request *req4 = NULL;
3345 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
3346 "Failed to setup up test directory: " BASEDIR);
3348 torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 6\n");
3349 io.generic.level = RAW_LOCK_LOCKX;
3351 /* Create the test file. */
3352 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3353 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
3354 "Failed to create %s - %s\n",
3355 fname, smbcli_errstr(cli->tree)));
3358 * a)
3359 * Lock regions 100->109, 120->129 as
3360 * two separate write locks in one request.
3362 io.lockx.level = RAW_LOCK_LOCKX;
3363 io.lockx.in.file.fnum = fnum;
3364 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3365 io.lockx.in.timeout = 0;
3366 io.lockx.in.ulock_cnt = 0;
3367 io.lockx.in.lock_cnt = 2;
3368 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3369 lock[0].pid = cli->session->pid;
3370 lock[0].offset = 100;
3371 lock[0].count = 10;
3372 lock[1].pid = cli->session->pid;
3373 lock[1].offset = 120;
3374 lock[1].count = 10;
3375 io.lockx.in.locks = &lock[0];
3376 status = smb_raw_lock(cli->tree, &io);
3377 CHECK_STATUS(status, NT_STATUS_OK);
3380 * b)
3381 * Now request the same locks on a different
3382 * context as blocking locks.
3383 * (read only)
3385 io.lockx.in.timeout = 20000;
3386 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
3387 lock[0].pid = cli->session->pid+1;
3388 lock[1].pid = cli->session->pid+1;
3389 req = smb_raw_lock_send(cli->tree, &io);
3390 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
3391 "Failed to setup timed locks (%s)\n", __location__));
3394 * c)
3395 * Request the first lock again on a separate context.
3396 * Wait 2 seconds. This should time out (the previous
3397 * multi-lock request should take precedence).
3399 io.lockx.in.timeout = 2000;
3400 io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3401 lock[0].pid = cli->session->pid+2;
3402 io.lockx.in.lock_cnt = 1;
3403 req2 = smb_raw_lock_send(cli->tree, &io);
3404 torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
3405 "Failed to setup timed locks (%s)\n", __location__));
3408 * d)
3409 * Lock regions 110->119
3411 io3.lockx.level = RAW_LOCK_LOCKX;
3412 io3.lockx.in.file.fnum = fnum;
3413 io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3414 io3.lockx.in.timeout = 0;
3415 io3.lockx.in.ulock_cnt = 0;
3416 io3.lockx.in.lock_cnt = 1;
3417 io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3418 lock3[0].pid = cli->session->pid+3;
3419 lock3[0].offset = 110;
3420 lock3[0].count = 10;
3421 io3.lockx.in.locks = &lock3[0];
3422 status = smb_raw_lock(cli->tree, &io3);
3423 CHECK_STATUS(status, NT_STATUS_OK);
3426 * e)
3427 * try 110-119 again
3429 io3.lockx.in.timeout = 20000;
3430 lock3[0].pid = cli->session->pid+4;
3431 req4 = smb_raw_lock_send(cli->tree, &io3);
3432 torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
3433 "Failed to setup timed locks (%s)\n", __location__));
3436 * f)
3437 * Unlock (a) lock[0] 100-109
3439 io.lockx.in.timeout = 0;
3440 io.lockx.in.ulock_cnt = 1;
3441 io.lockx.in.lock_cnt = 0;
3442 io.lockx.in.locks = &lock[0];
3443 lock[0].pid = cli->session->pid;
3444 status = smb_raw_lock(cli->tree, &io);
3445 CHECK_STATUS(status, NT_STATUS_OK);
3448 * g)
3449 * try to lock lock[0] 100-109 again
3451 lock[0].pid = cli->session->pid+5;
3452 io.lockx.in.ulock_cnt = 0;
3453 io.lockx.in.lock_cnt = 1;
3454 status = smb_raw_lock(cli->tree, &io);
3455 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3458 * h)
3459 * try to lock lock[0] 100-109 again with the pid (b)
3460 * that's still waiting
3462 lock[0].pid = cli->session->pid+1;
3463 io.lockx.in.ulock_cnt = 0;
3464 io.lockx.in.lock_cnt = 1;
3465 status = smb_raw_lock(cli->tree, &io);
3466 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3468 torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
3469 "req2 should still wait");
3472 * i)
3473 * Did the second lock (c) complete (should time out) ?
3475 status = smbcli_request_simple_recv(req2);
3476 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3478 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3479 "req should still wait");
3480 torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
3481 "req4 should still wait");
3484 * j)
3485 * Unlock (d) lock[0] 110-119
3487 io3.lockx.in.timeout = 0;
3488 io3.lockx.in.ulock_cnt = 1;
3489 io3.lockx.in.lock_cnt = 0;
3490 lock3[0].pid = cli->session->pid+3;
3491 status = smb_raw_lock(cli->tree, &io3);
3492 CHECK_STATUS(status, NT_STATUS_OK);
3495 * k)
3496 * receive the successful blocked lock request (e)
3497 * on 110-119 while (b) 100-109/120-129 is still waiting.
3499 status = smbcli_request_simple_recv(req4);
3500 CHECK_STATUS(status, NT_STATUS_OK);
3503 * l)
3504 * try to lock lock[0] 100-109 again
3506 lock[0].pid = cli->session->pid+6;
3507 io.lockx.in.ulock_cnt = 0;
3508 io.lockx.in.lock_cnt = 1;
3509 status = smb_raw_lock(cli->tree, &io);
3510 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3513 * m)
3514 * try to lock lock[0] 100-109 again with the pid (b)
3515 * that's still waiting
3517 lock[0].pid = cli->session->pid+1;
3518 io.lockx.in.ulock_cnt = 0;
3519 io.lockx.in.lock_cnt = 1;
3520 status = smb_raw_lock(cli->tree, &io);
3521 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3523 torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3524 "req should still wait");
3526 /* Start the clock. */
3527 t = time_mono(NULL);
3530 * n)
3531 * Unlock (a) lock[1] 120-129
3533 io.lockx.in.timeout = 0;
3534 io.lockx.in.ulock_cnt = 1;
3535 io.lockx.in.lock_cnt = 0;
3536 io.lockx.in.locks = &lock[1];
3537 lock[1].pid = cli->session->pid;
3538 status = smb_raw_lock(cli->tree, &io);
3539 CHECK_STATUS(status, NT_STATUS_OK);
3542 * o)
3543 * receive the successful blocked lock request (b)
3545 status = smbcli_request_simple_recv(req);
3546 CHECK_STATUS(status, NT_STATUS_OK);
3548 /* Fail if this took more than 2 seconds. */
3549 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
3550 "Blocking locks were not granted immediately (%s)\n",
3551 __location__));
3552 done:
3553 smb_raw_exit(cli->session);
3554 smbcli_deltree(cli->tree, BASEDIR);
3555 return ret;
3559 basic testing of lock calls
3561 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
3563 struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
3565 torture_suite_add_1smb_test(suite, "lockx", test_lockx);
3566 torture_suite_add_1smb_test(suite, "lock", test_lock);
3567 torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
3568 torture_suite_add_1smb_test(suite, "async", test_async);
3569 torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
3570 torture_suite_add_1smb_test(suite, "changetype", test_changetype);
3572 torture_suite_add_1smb_test(suite, "stacking", test_stacking);
3573 torture_suite_add_1smb_test(suite, "unlock", test_unlock);
3574 torture_suite_add_1smb_test(suite, "multiple_unlock",
3575 test_multiple_unlock);
3576 torture_suite_add_1smb_test(suite, "zerobytelocks", test_zerobytelocks);
3577 torture_suite_add_1smb_test(suite, "zerobyteread", test_zerobyteread);
3578 torture_suite_add_1smb_test(suite, "multilock", test_multilock);
3579 torture_suite_add_1smb_test(suite, "multilock2", test_multilock2);
3580 torture_suite_add_1smb_test(suite, "multilock3", test_multilock3);
3581 torture_suite_add_1smb_test(suite, "multilock4", test_multilock4);
3582 torture_suite_add_1smb_test(suite, "multilock5", test_multilock5);
3583 torture_suite_add_1smb_test(suite, "multilock6", test_multilock6);
3585 return suite;