s3: Optimize g_lock_lock for a heavily contended case
[Samba.git] / source4 / torture / raw / lock.c
blob0228837addccf5eeecebb48ef1fe8deeace8310c
1 /*
2 Unix SMB/CIFS implementation.
3 test suite for various lock operations
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "libcli/libcli.h"
27 #include "torture/util.h"
28 #include "libcli/composite/composite.h"
29 #include "libcli/smb_composite/smb_composite.h"
30 #include "lib/cmdline/popt_common.h"
31 #include "param/param.h"
33 #define CHECK_STATUS(status, correct) do { \
34 if (!NT_STATUS_EQUAL(status, correct)) { \
35 torture_result(tctx, TORTURE_FAIL, \
36 "(%s) Incorrect status %s - should be %s\n", \
37 __location__, nt_errstr(status), nt_errstr(correct)); \
38 ret = false; \
39 goto done; \
40 }} while (0)
42 #define CHECK_STATUS_CONT(status, correct) do { \
43 if (!NT_STATUS_EQUAL(status, correct)) { \
44 torture_result(tctx, TORTURE_FAIL, \
45 "(%s) Incorrect status %s - should be %s\n", \
46 __location__, nt_errstr(status), nt_errstr(correct)); \
47 ret = false; \
48 }} while (0)
50 #define CHECK_STATUS_OR(status, correct1, correct2) do { \
51 if ((!NT_STATUS_EQUAL(status, correct1)) && \
52 (!NT_STATUS_EQUAL(status, correct2))) { \
53 torture_result(tctx, TORTURE_FAIL, \
54 "(%s) Incorrect status %s - should be %s or %s\n", \
55 __location__, nt_errstr(status), nt_errstr(correct1), \
56 nt_errstr(correct2)); \
57 ret = false; \
58 goto done; \
59 }} while (0)
61 #define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \
62 if ((!NT_STATUS_EQUAL(status, correct1)) && \
63 (!NT_STATUS_EQUAL(status, correct2))) { \
64 torture_result(tctx, TORTURE_FAIL, \
65 "(%s) Incorrect status %s - should be %s or %s\n", \
66 __location__, nt_errstr(status), nt_errstr(correct1), \
67 nt_errstr(correct2)); \
68 ret = false; \
69 }} while (0)
70 #define BASEDIR "\\testlock"
72 #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
73 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
74 #define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
77 test SMBlock and SMBunlock ops
79 static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
81 union smb_lock io;
82 NTSTATUS status;
83 bool ret = true;
84 int fnum;
85 const char *fname = BASEDIR "\\test.txt";
87 if (!torture_setup_dir(cli, BASEDIR)) {
88 return false;
91 torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
92 io.generic.level = RAW_LOCK_LOCK;
94 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
95 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
96 "Failed to create %s - %s\n",
97 fname, smbcli_errstr(cli->tree)));
99 torture_comment(tctx, "Trying 0/0 lock\n");
100 io.lock.level = RAW_LOCK_LOCK;
101 io.lock.in.file.fnum = fnum;
102 io.lock.in.count = 0;
103 io.lock.in.offset = 0;
104 status = smb_raw_lock(cli->tree, &io);
105 CHECK_STATUS(status, NT_STATUS_OK);
106 cli->session->pid++;
107 status = smb_raw_lock(cli->tree, &io);
108 CHECK_STATUS(status, NT_STATUS_OK);
109 cli->session->pid--;
110 io.lock.level = RAW_LOCK_UNLOCK;
111 status = smb_raw_lock(cli->tree, &io);
112 CHECK_STATUS(status, NT_STATUS_OK);
114 torture_comment(tctx, "Trying 0/1 lock\n");
115 io.lock.level = RAW_LOCK_LOCK;
116 io.lock.in.file.fnum = fnum;
117 io.lock.in.count = 1;
118 io.lock.in.offset = 0;
119 status = smb_raw_lock(cli->tree, &io);
120 CHECK_STATUS(status, NT_STATUS_OK);
121 cli->session->pid++;
122 status = smb_raw_lock(cli->tree, &io);
123 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
124 cli->session->pid--;
125 io.lock.level = RAW_LOCK_UNLOCK;
126 status = smb_raw_lock(cli->tree, &io);
127 CHECK_STATUS(status, NT_STATUS_OK);
128 io.lock.level = RAW_LOCK_UNLOCK;
129 status = smb_raw_lock(cli->tree, &io);
130 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
132 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
133 io.lock.level = RAW_LOCK_LOCK;
134 io.lock.in.file.fnum = fnum;
135 io.lock.in.count = 4000;
136 io.lock.in.offset = 0xEEFFFFFF;
137 status = smb_raw_lock(cli->tree, &io);
138 CHECK_STATUS(status, NT_STATUS_OK);
139 cli->session->pid++;
140 status = smb_raw_lock(cli->tree, &io);
141 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
142 cli->session->pid--;
143 io.lock.level = RAW_LOCK_UNLOCK;
144 status = smb_raw_lock(cli->tree, &io);
145 CHECK_STATUS(status, NT_STATUS_OK);
146 io.lock.level = RAW_LOCK_UNLOCK;
147 status = smb_raw_lock(cli->tree, &io);
148 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
150 torture_comment(tctx, "Trying 0xEF000000 lock\n");
151 io.lock.level = RAW_LOCK_LOCK;
152 io.lock.in.file.fnum = fnum;
153 io.lock.in.count = 4000;
154 io.lock.in.offset = 0xEEFFFFFF;
155 status = smb_raw_lock(cli->tree, &io);
156 CHECK_STATUS(status, NT_STATUS_OK);
157 cli->session->pid++;
158 status = smb_raw_lock(cli->tree, &io);
159 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
160 cli->session->pid--;
161 io.lock.level = RAW_LOCK_UNLOCK;
162 status = smb_raw_lock(cli->tree, &io);
163 CHECK_STATUS(status, NT_STATUS_OK);
164 io.lock.level = RAW_LOCK_UNLOCK;
165 status = smb_raw_lock(cli->tree, &io);
166 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
168 torture_comment(tctx, "Trying max lock\n");
169 io.lock.level = RAW_LOCK_LOCK;
170 io.lock.in.file.fnum = fnum;
171 io.lock.in.count = 4000;
172 io.lock.in.offset = 0xEF000000;
173 status = smb_raw_lock(cli->tree, &io);
174 CHECK_STATUS(status, NT_STATUS_OK);
175 cli->session->pid++;
176 status = smb_raw_lock(cli->tree, &io);
177 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
178 cli->session->pid--;
179 io.lock.level = RAW_LOCK_UNLOCK;
180 status = smb_raw_lock(cli->tree, &io);
181 CHECK_STATUS(status, NT_STATUS_OK);
182 io.lock.level = RAW_LOCK_UNLOCK;
183 status = smb_raw_lock(cli->tree, &io);
184 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
186 torture_comment(tctx, "Trying wrong pid unlock\n");
187 io.lock.level = RAW_LOCK_LOCK;
188 io.lock.in.file.fnum = fnum;
189 io.lock.in.count = 4002;
190 io.lock.in.offset = 10001;
191 status = smb_raw_lock(cli->tree, &io);
192 CHECK_STATUS(status, NT_STATUS_OK);
193 cli->session->pid++;
194 io.lock.level = RAW_LOCK_UNLOCK;
195 status = smb_raw_lock(cli->tree, &io);
196 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
197 cli->session->pid--;
198 status = smb_raw_lock(cli->tree, &io);
199 CHECK_STATUS(status, NT_STATUS_OK);
201 done:
202 smbcli_close(cli->tree, fnum);
203 smb_raw_exit(cli->session);
204 smbcli_deltree(cli->tree, BASEDIR);
205 return ret;
210 test locking&X ops
212 static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
214 union smb_lock io;
215 struct smb_lock_entry lock[1];
216 NTSTATUS status;
217 bool ret = true;
218 int fnum;
219 const char *fname = BASEDIR "\\test.txt";
221 if (!torture_setup_dir(cli, BASEDIR)) {
222 return false;
225 torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
226 io.generic.level = RAW_LOCK_LOCKX;
228 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
229 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
230 "Failed to create %s - %s\n",
231 fname, smbcli_errstr(cli->tree)));
233 io.lockx.level = RAW_LOCK_LOCKX;
234 io.lockx.in.file.fnum = fnum;
235 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
236 io.lockx.in.timeout = 0;
237 io.lockx.in.ulock_cnt = 0;
238 io.lockx.in.lock_cnt = 1;
239 lock[0].pid = cli->session->pid;
240 lock[0].offset = 10;
241 lock[0].count = 1;
242 io.lockx.in.locks = &lock[0];
243 status = smb_raw_lock(cli->tree, &io);
244 CHECK_STATUS(status, NT_STATUS_OK);
247 torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
248 io.lockx.in.ulock_cnt = 0;
249 io.lockx.in.lock_cnt = 1;
250 lock[0].count = 4000;
251 lock[0].offset = 0xEEFFFFFF;
252 status = smb_raw_lock(cli->tree, &io);
253 CHECK_STATUS(status, NT_STATUS_OK);
254 lock[0].pid++;
255 status = smb_raw_lock(cli->tree, &io);
256 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
257 lock[0].pid--;
258 io.lockx.in.ulock_cnt = 1;
259 io.lockx.in.lock_cnt = 0;
260 status = smb_raw_lock(cli->tree, &io);
261 CHECK_STATUS(status, NT_STATUS_OK);
262 status = smb_raw_lock(cli->tree, &io);
263 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
265 torture_comment(tctx, "Trying 0xEF000000 lock\n");
266 io.lockx.in.ulock_cnt = 0;
267 io.lockx.in.lock_cnt = 1;
268 lock[0].count = 4000;
269 lock[0].offset = 0xEF000000;
270 status = smb_raw_lock(cli->tree, &io);
271 CHECK_STATUS(status, NT_STATUS_OK);
272 lock[0].pid++;
273 status = smb_raw_lock(cli->tree, &io);
274 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
275 lock[0].pid--;
276 io.lockx.in.ulock_cnt = 1;
277 io.lockx.in.lock_cnt = 0;
278 status = smb_raw_lock(cli->tree, &io);
279 CHECK_STATUS(status, NT_STATUS_OK);
280 status = smb_raw_lock(cli->tree, &io);
281 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
283 torture_comment(tctx, "Trying zero lock\n");
284 io.lockx.in.ulock_cnt = 0;
285 io.lockx.in.lock_cnt = 1;
286 lock[0].count = 0;
287 lock[0].offset = ~0;
288 status = smb_raw_lock(cli->tree, &io);
289 CHECK_STATUS(status, NT_STATUS_OK);
290 lock[0].pid++;
291 status = smb_raw_lock(cli->tree, &io);
292 CHECK_STATUS(status, NT_STATUS_OK);
293 lock[0].pid--;
294 io.lockx.in.ulock_cnt = 1;
295 io.lockx.in.lock_cnt = 0;
296 status = smb_raw_lock(cli->tree, &io);
297 CHECK_STATUS(status, NT_STATUS_OK);
298 status = smb_raw_lock(cli->tree, &io);
299 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
301 torture_comment(tctx, "Trying max lock\n");
302 io.lockx.in.ulock_cnt = 0;
303 io.lockx.in.lock_cnt = 1;
304 lock[0].count = 0;
305 lock[0].offset = ~0;
306 status = smb_raw_lock(cli->tree, &io);
307 CHECK_STATUS(status, NT_STATUS_OK);
308 lock[0].pid++;
309 status = smb_raw_lock(cli->tree, &io);
310 CHECK_STATUS(status, NT_STATUS_OK);
311 lock[0].pid--;
312 io.lockx.in.ulock_cnt = 1;
313 io.lockx.in.lock_cnt = 0;
314 status = smb_raw_lock(cli->tree, &io);
315 CHECK_STATUS(status, NT_STATUS_OK);
316 status = smb_raw_lock(cli->tree, &io);
317 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
319 torture_comment(tctx, "Trying 2^63\n");
320 io.lockx.in.ulock_cnt = 0;
321 io.lockx.in.lock_cnt = 1;
322 lock[0].count = 1;
323 lock[0].offset = 1;
324 lock[0].offset <<= 63;
325 status = smb_raw_lock(cli->tree, &io);
326 CHECK_STATUS(status, NT_STATUS_OK);
327 lock[0].pid++;
328 status = smb_raw_lock(cli->tree, &io);
329 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
330 lock[0].pid--;
331 io.lockx.in.ulock_cnt = 1;
332 io.lockx.in.lock_cnt = 0;
333 status = smb_raw_lock(cli->tree, &io);
334 CHECK_STATUS(status, NT_STATUS_OK);
335 status = smb_raw_lock(cli->tree, &io);
336 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
338 torture_comment(tctx, "Trying 2^63 - 1\n");
339 io.lockx.in.ulock_cnt = 0;
340 io.lockx.in.lock_cnt = 1;
341 lock[0].count = 1;
342 lock[0].offset = 1;
343 lock[0].offset <<= 63;
344 lock[0].offset--;
345 status = smb_raw_lock(cli->tree, &io);
346 CHECK_STATUS(status, NT_STATUS_OK);
347 lock[0].pid++;
348 status = smb_raw_lock(cli->tree, &io);
349 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
350 lock[0].pid--;
351 io.lockx.in.ulock_cnt = 1;
352 io.lockx.in.lock_cnt = 0;
353 status = smb_raw_lock(cli->tree, &io);
354 CHECK_STATUS(status, NT_STATUS_OK);
355 status = smb_raw_lock(cli->tree, &io);
356 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
358 torture_comment(tctx, "Trying max lock 2\n");
359 io.lockx.in.ulock_cnt = 0;
360 io.lockx.in.lock_cnt = 1;
361 lock[0].count = 1;
362 lock[0].offset = ~0;
363 status = smb_raw_lock(cli->tree, &io);
364 CHECK_STATUS(status, NT_STATUS_OK);
365 lock[0].pid++;
366 lock[0].count = 2;
367 status = smb_raw_lock(cli->tree, &io);
368 if (TARGET_IS_WIN7(tctx))
369 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
370 else
371 CHECK_STATUS(status, NT_STATUS_OK);
372 lock[0].pid--;
373 io.lockx.in.ulock_cnt = 1;
374 io.lockx.in.lock_cnt = 0;
375 lock[0].count = 1;
376 status = smb_raw_lock(cli->tree, &io);
378 CHECK_STATUS(status, NT_STATUS_OK);
379 status = smb_raw_lock(cli->tree, &io);
380 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
382 done:
383 smbcli_close(cli->tree, fnum);
384 smb_raw_exit(cli->session);
385 smbcli_deltree(cli->tree, BASEDIR);
386 return ret;
390 test high pid
392 static bool test_pidhigh(struct torture_context *tctx,
393 struct smbcli_state *cli)
395 union smb_lock io;
396 struct smb_lock_entry lock[1];
397 NTSTATUS status;
398 bool ret = true;
399 int fnum;
400 const char *fname = BASEDIR "\\test.txt";
401 uint8_t c = 1;
403 if (!torture_setup_dir(cli, BASEDIR)) {
404 return false;
407 torture_comment(tctx, "Testing high pid\n");
408 io.generic.level = RAW_LOCK_LOCKX;
410 cli->session->pid = 1;
412 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
413 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
414 "Failed to create %s - %s\n",
415 fname, smbcli_errstr(cli->tree)));
417 if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
418 torture_result(tctx, TORTURE_FAIL,
419 "Failed to write 1 byte - %s\n",
420 smbcli_errstr(cli->tree));
421 ret = false;
422 goto done;
425 io.lockx.level = RAW_LOCK_LOCKX;
426 io.lockx.in.file.fnum = fnum;
427 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
428 io.lockx.in.timeout = 0;
429 io.lockx.in.ulock_cnt = 0;
430 io.lockx.in.lock_cnt = 1;
431 lock[0].pid = cli->session->pid;
432 lock[0].offset = 0;
433 lock[0].count = 0xFFFFFFFF;
434 io.lockx.in.locks = &lock[0];
435 status = smb_raw_lock(cli->tree, &io);
436 CHECK_STATUS(status, NT_STATUS_OK);
438 if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
439 torture_result(tctx, TORTURE_FAIL,
440 "Failed to read 1 byte - %s\n",
441 smbcli_errstr(cli->tree));
442 ret = false;
443 goto done;
446 cli->session->pid = 2;
448 if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
449 torture_result(tctx, TORTURE_FAIL,
450 "pid is incorrect handled for read with lock!\n");
451 ret = false;
452 goto done;
455 cli->session->pid = 0x10001;
457 if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
458 torture_result(tctx, TORTURE_FAIL,
459 "High pid is used on this server!\n");
460 ret = false;
461 } else {
462 torture_warning(tctx, "High pid is not used on this server (correct)\n");
465 done:
466 smbcli_close(cli->tree, fnum);
467 smb_raw_exit(cli->session);
468 smbcli_deltree(cli->tree, BASEDIR);
469 return ret;
474 test locking&X async operation
476 static bool test_async(struct torture_context *tctx,
477 struct smbcli_state *cli)
479 struct smbcli_session *session;
480 struct smb_composite_sesssetup setup;
481 struct smbcli_tree *tree;
482 union smb_tcon tcon;
483 const char *host, *share;
484 union smb_lock io;
485 struct smb_lock_entry lock[2];
486 NTSTATUS status;
487 bool ret = true;
488 int fnum;
489 const char *fname = BASEDIR "\\test.txt";
490 time_t t;
491 struct smbcli_request *req;
492 struct smbcli_session_options options;
494 if (!torture_setup_dir(cli, BASEDIR)) {
495 return false;
498 lp_smbcli_session_options(tctx->lp_ctx, &options);
500 torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
501 io.generic.level = RAW_LOCK_LOCKX;
503 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
504 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
505 "Failed to create %s - %s\n",
506 fname, smbcli_errstr(cli->tree)));
508 io.lockx.level = RAW_LOCK_LOCKX;
509 io.lockx.in.file.fnum = fnum;
510 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
511 io.lockx.in.timeout = 0;
512 io.lockx.in.ulock_cnt = 0;
513 io.lockx.in.lock_cnt = 1;
514 lock[0].pid = cli->session->pid;
515 lock[0].offset = 100;
516 lock[0].count = 10;
517 io.lockx.in.locks = &lock[0];
518 status = smb_raw_lock(cli->tree, &io);
519 CHECK_STATUS(status, NT_STATUS_OK);
521 t = time(NULL);
523 torture_comment(tctx, "testing cancel by CANCEL_LOCK\n");
525 /* setup a timed lock */
526 io.lockx.in.timeout = 10000;
527 req = smb_raw_lock_send(cli->tree, &io);
528 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
529 "Failed to setup timed lock (%s)\n", __location__));
531 /* cancel the wrong range */
532 lock[0].offset = 0;
533 io.lockx.in.timeout = 0;
534 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
535 status = smb_raw_lock(cli->tree, &io);
536 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
538 /* cancel with the wrong bits set */
539 lock[0].offset = 100;
540 io.lockx.in.timeout = 0;
541 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
542 status = smb_raw_lock(cli->tree, &io);
543 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
545 /* cancel the right range */
546 lock[0].offset = 100;
547 io.lockx.in.timeout = 0;
548 io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
549 status = smb_raw_lock(cli->tree, &io);
550 CHECK_STATUS(status, NT_STATUS_OK);
552 /* receive the failed lock request */
553 status = smbcli_request_simple_recv(req);
554 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
556 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
557 "lock cancel was not immediate (%s)\n", __location__));
559 torture_comment(tctx, "testing cancel by unlock\n");
560 io.lockx.in.ulock_cnt = 0;
561 io.lockx.in.lock_cnt = 1;
562 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
563 io.lockx.in.timeout = 0;
564 status = smb_raw_lock(cli->tree, &io);
565 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
567 io.lockx.in.timeout = 5000;
568 req = smb_raw_lock_send(cli->tree, &io);
569 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
570 "Failed to setup timed lock (%s)\n", __location__));
572 io.lockx.in.ulock_cnt = 1;
573 io.lockx.in.lock_cnt = 0;
574 status = smb_raw_lock(cli->tree, &io);
575 CHECK_STATUS(status, NT_STATUS_OK);
577 t = time(NULL);
578 status = smbcli_request_simple_recv(req);
579 CHECK_STATUS(status, NT_STATUS_OK);
581 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
582 "lock cancel by unlock was not immediate (%s) - took %d secs\n",
583 __location__, (int)(time(NULL)-t)));
585 torture_comment(tctx, "testing cancel by close\n");
586 io.lockx.in.ulock_cnt = 0;
587 io.lockx.in.lock_cnt = 1;
588 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
589 io.lockx.in.timeout = 0;
590 status = smb_raw_lock(cli->tree, &io);
591 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
593 t = time(NULL);
594 io.lockx.in.timeout = 10000;
595 req = smb_raw_lock_send(cli->tree, &io);
596 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
597 "Failed to setup timed lock (%s)\n", __location__));
599 status = smbcli_close(cli->tree, fnum);
600 CHECK_STATUS(status, NT_STATUS_OK);
602 status = smbcli_request_simple_recv(req);
603 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
605 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
606 "lock cancel by close was not immediate (%s)\n", __location__));
608 torture_comment(tctx, "create a new sessions\n");
609 session = smbcli_session_init(cli->transport, tctx, false, options);
610 setup.in.sesskey = cli->transport->negotiate.sesskey;
611 setup.in.capabilities = cli->transport->negotiate.capabilities;
612 setup.in.workgroup = lp_workgroup(tctx->lp_ctx);
613 setup.in.credentials = cmdline_credentials;
614 setup.in.gensec_settings = lp_gensec_settings(tctx, tctx->lp_ctx);
615 status = smb_composite_sesssetup(session, &setup);
616 CHECK_STATUS(status, NT_STATUS_OK);
617 session->vuid = setup.out.vuid;
619 torture_comment(tctx, "create new tree context\n");
620 share = torture_setting_string(tctx, "share", NULL);
621 host = torture_setting_string(tctx, "host", NULL);
622 tree = smbcli_tree_init(session, tctx, false);
623 tcon.generic.level = RAW_TCON_TCONX;
624 tcon.tconx.in.flags = 0;
625 tcon.tconx.in.password = data_blob(NULL, 0);
626 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
627 tcon.tconx.in.device = "A:";
628 status = smb_raw_tcon(tree, tctx, &tcon);
629 CHECK_STATUS(status, NT_STATUS_OK);
630 tree->tid = tcon.tconx.out.tid;
632 torture_comment(tctx, "testing cancel by exit\n");
633 fname = BASEDIR "\\test_exit.txt";
634 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
635 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
636 "Failed to reopen %s - %s\n",
637 fname, smbcli_errstr(tree)));
639 io.lockx.level = RAW_LOCK_LOCKX;
640 io.lockx.in.file.fnum = fnum;
641 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
642 io.lockx.in.timeout = 0;
643 io.lockx.in.ulock_cnt = 0;
644 io.lockx.in.lock_cnt = 1;
645 lock[0].pid = session->pid;
646 lock[0].offset = 100;
647 lock[0].count = 10;
648 io.lockx.in.locks = &lock[0];
649 status = smb_raw_lock(tree, &io);
650 CHECK_STATUS(status, NT_STATUS_OK);
652 io.lockx.in.ulock_cnt = 0;
653 io.lockx.in.lock_cnt = 1;
654 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
655 io.lockx.in.timeout = 0;
656 status = smb_raw_lock(tree, &io);
657 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
659 io.lockx.in.timeout = 10000;
660 t = time(NULL);
661 req = smb_raw_lock_send(tree, &io);
662 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
663 "Failed to setup timed lock (%s)\n", __location__));
665 status = smb_raw_exit(session);
666 CHECK_STATUS(status, NT_STATUS_OK);
668 status = smbcli_request_simple_recv(req);
669 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
671 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
672 "lock cancel by exit was not immediate (%s)\n", __location__));
674 torture_comment(tctx, "testing cancel by ulogoff\n");
675 fname = BASEDIR "\\test_ulogoff.txt";
676 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
677 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
678 "Failed to reopen %s - %s\n",
679 fname, smbcli_errstr(tree)));
681 io.lockx.level = RAW_LOCK_LOCKX;
682 io.lockx.in.file.fnum = fnum;
683 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
684 io.lockx.in.timeout = 0;
685 io.lockx.in.ulock_cnt = 0;
686 io.lockx.in.lock_cnt = 1;
687 lock[0].pid = session->pid;
688 lock[0].offset = 100;
689 lock[0].count = 10;
690 io.lockx.in.locks = &lock[0];
691 status = smb_raw_lock(tree, &io);
692 CHECK_STATUS(status, NT_STATUS_OK);
694 io.lockx.in.ulock_cnt = 0;
695 io.lockx.in.lock_cnt = 1;
696 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
697 io.lockx.in.timeout = 0;
698 status = smb_raw_lock(tree, &io);
699 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
701 io.lockx.in.timeout = 10000;
702 t = time(NULL);
703 req = smb_raw_lock_send(tree, &io);
704 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
705 "Failed to setup timed lock (%s)\n", __location__));
707 status = smb_raw_ulogoff(session);
708 CHECK_STATUS(status, NT_STATUS_OK);
710 status = smbcli_request_simple_recv(req);
711 if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
712 torture_result(tctx, TORTURE_FAIL,
713 "lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n",
714 nt_errstr(status));
715 smb_tree_disconnect(tree);
716 smb_raw_exit(session);
717 goto done;
719 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
721 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
722 "lock cancel by ulogoff was not immediate (%s)\n", __location__));
724 torture_comment(tctx, "testing cancel by tdis\n");
725 tree->session = cli->session;
727 fname = BASEDIR "\\test_tdis.txt";
728 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
729 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
730 "Failed to reopen %s - %s\n",
731 fname, smbcli_errstr(tree)));
733 io.lockx.level = RAW_LOCK_LOCKX;
734 io.lockx.in.file.fnum = fnum;
735 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
736 io.lockx.in.timeout = 0;
737 io.lockx.in.ulock_cnt = 0;
738 io.lockx.in.lock_cnt = 1;
739 lock[0].pid = cli->session->pid;
740 lock[0].offset = 100;
741 lock[0].count = 10;
742 io.lockx.in.locks = &lock[0];
743 status = smb_raw_lock(tree, &io);
744 CHECK_STATUS(status, NT_STATUS_OK);
746 status = smb_raw_lock(tree, &io);
747 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
749 io.lockx.in.timeout = 10000;
750 t = time(NULL);
751 req = smb_raw_lock_send(tree, &io);
752 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
753 "Failed to setup timed lock (%s)\n", __location__));
755 status = smb_tree_disconnect(tree);
756 CHECK_STATUS(status, NT_STATUS_OK);
758 status = smbcli_request_simple_recv(req);
759 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
761 torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
762 "lock cancel by tdis was not immediate (%s)\n", __location__));
764 done:
765 smb_raw_exit(cli->session);
766 smbcli_deltree(cli->tree, BASEDIR);
767 return ret;
771 test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
773 static bool test_errorcode(struct torture_context *tctx,
774 struct smbcli_state *cli)
776 union smb_lock io;
777 union smb_open op;
778 struct smb_lock_entry lock[2];
779 NTSTATUS status;
780 bool ret = true;
781 int fnum, fnum2;
782 const char *fname;
783 struct smbcli_request *req;
784 time_t start;
785 int t;
786 int delay;
788 if (!torture_setup_dir(cli, BASEDIR)) {
789 return false;
792 torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
794 torture_comment(tctx, "testing with timeout = 0\n");
795 fname = BASEDIR "\\test0.txt";
796 t = 0;
799 * the first run is with t = 0,
800 * the second with t > 0 (=1)
802 next_run:
804 * use the DENY_DOS mode, that creates two fnum's of one low-level file handle,
805 * this demonstrates that the cache is per fnum
807 op.openx.level = RAW_OPEN_OPENX;
808 op.openx.in.fname = fname;
809 op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
810 op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS;
811 op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
812 op.openx.in.search_attrs = 0;
813 op.openx.in.file_attrs = 0;
814 op.openx.in.write_time = 0;
815 op.openx.in.size = 0;
816 op.openx.in.timeout = 0;
818 status = smb_raw_open(cli->tree, tctx, &op);
819 CHECK_STATUS(status, NT_STATUS_OK);
820 fnum = op.openx.out.file.fnum;
822 status = smb_raw_open(cli->tree, tctx, &op);
823 CHECK_STATUS(status, NT_STATUS_OK);
824 fnum2 = op.openx.out.file.fnum;
826 io.lockx.level = RAW_LOCK_LOCKX;
827 io.lockx.in.file.fnum = fnum;
828 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
829 io.lockx.in.timeout = t;
830 io.lockx.in.ulock_cnt = 0;
831 io.lockx.in.lock_cnt = 1;
832 lock[0].pid = cli->session->pid;
833 lock[0].offset = 100;
834 lock[0].count = 10;
835 io.lockx.in.locks = &lock[0];
836 status = smb_raw_lock(cli->tree, &io);
837 CHECK_STATUS(status, NT_STATUS_OK);
840 * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
841 * this also demonstrates that the error code cache is per file handle
842 * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
844 io.lockx.in.file.fnum = fnum2;
845 status = smb_raw_lock(cli->tree, &io);
846 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
848 io.lockx.in.file.fnum = fnum;
849 status = smb_raw_lock(cli->tree, &io);
850 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
852 /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
853 io.lockx.in.file.fnum = fnum;
854 status = smb_raw_lock(cli->tree, &io);
855 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
857 io.lockx.in.file.fnum = fnum2;
858 status = smb_raw_lock(cli->tree, &io);
859 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
861 io.lockx.in.file.fnum = fnum;
862 status = smb_raw_lock(cli->tree, &io);
863 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
865 io.lockx.in.file.fnum = fnum2;
866 status = smb_raw_lock(cli->tree, &io);
867 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
869 /* demonstrate that the smbpid doesn't matter */
870 lock[0].pid++;
871 io.lockx.in.file.fnum = fnum;
872 status = smb_raw_lock(cli->tree, &io);
873 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
875 io.lockx.in.file.fnum = fnum2;
876 status = smb_raw_lock(cli->tree, &io);
877 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
878 lock[0].pid--;
881 * demonstrate the a successful lock with count = 0 and the same offset,
882 * doesn't reset the error cache
884 lock[0].offset = 100;
885 lock[0].count = 0;
886 io.lockx.in.file.fnum = fnum;
887 status = smb_raw_lock(cli->tree, &io);
888 CHECK_STATUS(status, NT_STATUS_OK);
890 io.lockx.in.file.fnum = fnum2;
891 status = smb_raw_lock(cli->tree, &io);
892 CHECK_STATUS(status, NT_STATUS_OK);
894 lock[0].offset = 100;
895 lock[0].count = 10;
896 io.lockx.in.file.fnum = fnum;
897 status = smb_raw_lock(cli->tree, &io);
898 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
900 io.lockx.in.file.fnum = fnum2;
901 status = smb_raw_lock(cli->tree, &io);
902 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
905 * demonstrate the a successful lock with count = 0 and outside the locked range,
906 * doesn't reset the error cache
908 lock[0].offset = 110;
909 lock[0].count = 0;
910 io.lockx.in.file.fnum = fnum;
911 status = smb_raw_lock(cli->tree, &io);
912 CHECK_STATUS(status, NT_STATUS_OK);
914 io.lockx.in.file.fnum = fnum2;
915 status = smb_raw_lock(cli->tree, &io);
916 CHECK_STATUS(status, NT_STATUS_OK);
918 lock[0].offset = 100;
919 lock[0].count = 10;
920 io.lockx.in.file.fnum = fnum;
921 status = smb_raw_lock(cli->tree, &io);
922 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
924 io.lockx.in.file.fnum = fnum2;
925 status = smb_raw_lock(cli->tree, &io);
926 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
928 lock[0].offset = 99;
929 lock[0].count = 0;
930 io.lockx.in.file.fnum = fnum;
931 status = smb_raw_lock(cli->tree, &io);
932 CHECK_STATUS(status, NT_STATUS_OK);
934 io.lockx.in.file.fnum = fnum2;
935 status = smb_raw_lock(cli->tree, &io);
936 CHECK_STATUS(status, NT_STATUS_OK);
938 lock[0].offset = 100;
939 lock[0].count = 10;
940 io.lockx.in.file.fnum = fnum;
941 status = smb_raw_lock(cli->tree, &io);
942 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
944 io.lockx.in.file.fnum = fnum2;
945 status = smb_raw_lock(cli->tree, &io);
946 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
948 /* demonstrate that a changing count doesn't reset the error cache */
949 lock[0].offset = 100;
950 lock[0].count = 5;
951 io.lockx.in.file.fnum = fnum;
952 status = smb_raw_lock(cli->tree, &io);
953 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
955 io.lockx.in.file.fnum = fnum2;
956 status = smb_raw_lock(cli->tree, &io);
957 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
959 lock[0].offset = 100;
960 lock[0].count = 15;
961 io.lockx.in.file.fnum = fnum;
962 status = smb_raw_lock(cli->tree, &io);
963 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
965 io.lockx.in.file.fnum = fnum2;
966 status = smb_raw_lock(cli->tree, &io);
967 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
970 * demonstrate the a lock with count = 0 and inside the locked range,
971 * fails and resets the error cache
973 lock[0].offset = 101;
974 lock[0].count = 0;
975 io.lockx.in.file.fnum = fnum;
976 status = smb_raw_lock(cli->tree, &io);
977 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
978 status = smb_raw_lock(cli->tree, &io);
979 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
981 io.lockx.in.file.fnum = fnum2;
982 status = smb_raw_lock(cli->tree, &io);
983 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
984 status = smb_raw_lock(cli->tree, &io);
985 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
987 lock[0].offset = 100;
988 lock[0].count = 10;
989 io.lockx.in.file.fnum = fnum;
990 status = smb_raw_lock(cli->tree, &io);
991 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
992 status = smb_raw_lock(cli->tree, &io);
993 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
995 io.lockx.in.file.fnum = fnum2;
996 status = smb_raw_lock(cli->tree, &io);
997 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
998 status = smb_raw_lock(cli->tree, &io);
999 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1001 /* demonstrate the a changing offset, resets the error cache */
1002 lock[0].offset = 105;
1003 lock[0].count = 10;
1004 io.lockx.in.file.fnum = fnum;
1005 status = smb_raw_lock(cli->tree, &io);
1006 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1007 status = smb_raw_lock(cli->tree, &io);
1008 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1010 io.lockx.in.file.fnum = fnum2;
1011 status = smb_raw_lock(cli->tree, &io);
1012 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1013 status = smb_raw_lock(cli->tree, &io);
1014 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1016 lock[0].offset = 100;
1017 lock[0].count = 10;
1018 io.lockx.in.file.fnum = fnum;
1019 status = smb_raw_lock(cli->tree, &io);
1020 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1021 status = smb_raw_lock(cli->tree, &io);
1022 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1024 io.lockx.in.file.fnum = fnum2;
1025 status = smb_raw_lock(cli->tree, &io);
1026 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1027 status = smb_raw_lock(cli->tree, &io);
1028 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1030 lock[0].offset = 95;
1031 lock[0].count = 9;
1032 io.lockx.in.file.fnum = fnum;
1033 status = smb_raw_lock(cli->tree, &io);
1034 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1035 status = smb_raw_lock(cli->tree, &io);
1036 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1038 io.lockx.in.file.fnum = fnum2;
1039 status = smb_raw_lock(cli->tree, &io);
1040 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1041 status = smb_raw_lock(cli->tree, &io);
1042 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1044 lock[0].offset = 100;
1045 lock[0].count = 10;
1046 io.lockx.in.file.fnum = fnum;
1047 status = smb_raw_lock(cli->tree, &io);
1048 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1049 status = smb_raw_lock(cli->tree, &io);
1050 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1052 io.lockx.in.file.fnum = fnum2;
1053 status = smb_raw_lock(cli->tree, &io);
1054 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1055 status = smb_raw_lock(cli->tree, &io);
1056 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1059 * demonstrate the a successful lock in a different range,
1060 * doesn't reset the cache, the failing lock on the 2nd handle
1061 * resets the resets the cache
1063 lock[0].offset = 120;
1064 lock[0].count = 15;
1065 io.lockx.in.file.fnum = fnum;
1066 status = smb_raw_lock(cli->tree, &io);
1067 CHECK_STATUS(status, NT_STATUS_OK);
1069 io.lockx.in.file.fnum = fnum2;
1070 status = smb_raw_lock(cli->tree, &io);
1071 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1073 lock[0].offset = 100;
1074 lock[0].count = 10;
1075 io.lockx.in.file.fnum = fnum;
1076 status = smb_raw_lock(cli->tree, &io);
1077 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1078 status = smb_raw_lock(cli->tree, &io);
1079 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1081 io.lockx.in.file.fnum = fnum2;
1082 status = smb_raw_lock(cli->tree, &io);
1083 CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1084 status = smb_raw_lock(cli->tree, &io);
1085 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1087 /* end of the loop */
1088 if (t == 0) {
1089 smb_raw_exit(cli->session);
1090 t = 1;
1091 torture_comment(tctx, "testing with timeout > 0 (=%d)\n",
1093 fname = BASEDIR "\\test1.txt";
1094 goto next_run;
1097 t = 4000;
1098 torture_comment(tctx, "testing special cases with timeout > 0 (=%d)\n",
1102 * the following 3 test sections demonstrate that
1103 * the cache is only set when the error is reported
1104 * to the client (after the timeout went by)
1106 smb_raw_exit(cli->session);
1107 torture_comment(tctx, "testing a conflict while a lock is pending\n");
1108 fname = BASEDIR "\\test2.txt";
1109 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1110 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1111 "Failed to reopen %s - %s\n",
1112 fname, smbcli_errstr(cli->tree)));
1114 io.lockx.level = RAW_LOCK_LOCKX;
1115 io.lockx.in.file.fnum = fnum;
1116 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1117 io.lockx.in.timeout = 0;
1118 io.lockx.in.ulock_cnt = 0;
1119 io.lockx.in.lock_cnt = 1;
1120 lock[0].pid = cli->session->pid;
1121 lock[0].offset = 100;
1122 lock[0].count = 10;
1123 io.lockx.in.locks = &lock[0];
1124 status = smb_raw_lock(cli->tree, &io);
1125 CHECK_STATUS(status, NT_STATUS_OK);
1127 start = time(NULL);
1128 io.lockx.in.timeout = t;
1129 req = smb_raw_lock_send(cli->tree, &io);
1130 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1131 "Failed to setup timed lock (%s)\n", __location__));
1133 io.lockx.in.timeout = 0;
1134 lock[0].offset = 105;
1135 lock[0].count = 10;
1136 status = smb_raw_lock(cli->tree, &io);
1137 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1139 status = smbcli_request_simple_recv(req);
1140 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1142 delay = t / 1000;
1143 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1144 delay /= 2;
1147 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1148 "lock comes back to early timeout[%d] delay[%d]"
1149 "(%s)\n", t, delay, __location__));
1151 status = smb_raw_lock(cli->tree, &io);
1152 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1154 smbcli_close(cli->tree, fnum);
1155 fname = BASEDIR "\\test3.txt";
1156 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1157 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1158 "Failed to reopen %s - %s\n",
1159 fname, smbcli_errstr(cli->tree)));
1161 io.lockx.level = RAW_LOCK_LOCKX;
1162 io.lockx.in.file.fnum = fnum;
1163 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1164 io.lockx.in.timeout = 0;
1165 io.lockx.in.ulock_cnt = 0;
1166 io.lockx.in.lock_cnt = 1;
1167 lock[0].pid = cli->session->pid;
1168 lock[0].offset = 100;
1169 lock[0].count = 10;
1170 io.lockx.in.locks = &lock[0];
1171 status = smb_raw_lock(cli->tree, &io);
1172 CHECK_STATUS(status, NT_STATUS_OK);
1174 start = time(NULL);
1175 io.lockx.in.timeout = t;
1176 req = smb_raw_lock_send(cli->tree, &io);
1177 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1178 "Failed to setup timed lock (%s)\n", __location__));
1180 io.lockx.in.timeout = 0;
1181 lock[0].offset = 105;
1182 lock[0].count = 10;
1183 status = smb_raw_lock(cli->tree, &io);
1184 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1186 status = smbcli_request_simple_recv(req);
1187 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1189 delay = t / 1000;
1190 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1191 delay /= 2;
1194 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1195 "lock comes back to early timeout[%d] delay[%d]"
1196 "(%s)\n", t, delay, __location__));
1198 lock[0].offset = 100;
1199 lock[0].count = 10;
1200 status = smb_raw_lock(cli->tree, &io);
1201 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1203 smbcli_close(cli->tree, fnum);
1204 fname = BASEDIR "\\test4.txt";
1205 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1206 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1207 "Failed to reopen %s - %s\n",
1208 fname, smbcli_errstr(cli->tree)));
1210 io.lockx.level = RAW_LOCK_LOCKX;
1211 io.lockx.in.file.fnum = fnum;
1212 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1213 io.lockx.in.timeout = 0;
1214 io.lockx.in.ulock_cnt = 0;
1215 io.lockx.in.lock_cnt = 1;
1216 lock[0].pid = cli->session->pid;
1217 lock[0].offset = 100;
1218 lock[0].count = 10;
1219 io.lockx.in.locks = &lock[0];
1220 status = smb_raw_lock(cli->tree, &io);
1221 CHECK_STATUS(status, NT_STATUS_OK);
1223 start = time(NULL);
1224 io.lockx.in.timeout = t;
1225 req = smb_raw_lock_send(cli->tree, &io);
1226 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1227 "Failed to setup timed lock (%s)\n", __location__));
1229 io.lockx.in.timeout = 0;
1230 status = smb_raw_lock(cli->tree, &io);
1231 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1233 status = smbcli_request_simple_recv(req);
1234 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1236 delay = t / 1000;
1237 if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1238 delay /= 2;
1241 torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1242 "lock comes back to early timeout[%d] delay[%d]"
1243 "(%s)\n", t, delay, __location__));
1245 status = smb_raw_lock(cli->tree, &io);
1246 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1248 done:
1249 smb_raw_exit(cli->session);
1250 smbcli_deltree(cli->tree, BASEDIR);
1251 return ret;
1256 test LOCKING_ANDX_CHANGE_LOCKTYPE
1258 static bool test_changetype(struct torture_context *tctx,
1259 struct smbcli_state *cli)
1261 union smb_lock io;
1262 struct smb_lock_entry lock[2];
1263 NTSTATUS status;
1264 bool ret = true;
1265 int fnum;
1266 uint8_t c = 0;
1267 const char *fname = BASEDIR "\\test.txt";
1269 if (!torture_setup_dir(cli, BASEDIR)) {
1270 return false;
1273 torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1274 io.generic.level = RAW_LOCK_LOCKX;
1276 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1277 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1278 "Failed to create %s - %s\n",
1279 fname, smbcli_errstr(cli->tree)));
1281 io.lockx.level = RAW_LOCK_LOCKX;
1282 io.lockx.in.file.fnum = fnum;
1283 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1284 io.lockx.in.timeout = 0;
1285 io.lockx.in.ulock_cnt = 0;
1286 io.lockx.in.lock_cnt = 1;
1287 lock[0].pid = cli->session->pid;
1288 lock[0].offset = 100;
1289 lock[0].count = 10;
1290 io.lockx.in.locks = &lock[0];
1291 status = smb_raw_lock(cli->tree, &io);
1292 CHECK_STATUS(status, NT_STATUS_OK);
1294 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1295 torture_result(tctx, TORTURE_FAIL,
1296 "allowed write on read locked region (%s)\n", __location__);
1297 ret = false;
1298 goto done;
1301 /* windows server don't seem to support this */
1302 io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1303 status = smb_raw_lock(cli->tree, &io);
1304 CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1306 if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1307 torture_result(tctx, TORTURE_FAIL,
1308 "allowed write after lock change (%s)\n", __location__);
1309 ret = false;
1310 goto done;
1313 done:
1314 smbcli_close(cli->tree, fnum);
1315 smb_raw_exit(cli->session);
1316 smbcli_deltree(cli->tree, BASEDIR);
1317 return ret;
1320 struct double_lock_test {
1321 struct smb_lock_entry lock1;
1322 struct smb_lock_entry lock2;
1323 NTSTATUS exp_status;
1327 * Tests zero byte locks.
1329 static const struct double_lock_test zero_byte_tests[] = {
1330 /* {pid, offset, count}, {pid, offset, count}, status */
1332 /** First, takes a zero byte lock at offset 10. Then:
1333 * - Taking 0 byte lock at 10 should succeed.
1334 * - Taking 1 byte locks at 9,10,11 should succeed.
1335 * - Taking 2 byte lock at 9 should fail.
1336 * - Taking 2 byte lock at 10 should succeed.
1337 * - Taking 3 byte lock at 9 should fail.
1339 {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1340 {{1000, 10, 0}, {1001, 9, 1}, NT_STATUS_OK},
1341 {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1342 {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1343 {{1000, 10, 0}, {1001, 9, 2}, NT_STATUS_LOCK_NOT_GRANTED},
1344 {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1345 {{1000, 10, 0}, {1001, 9, 3}, NT_STATUS_LOCK_NOT_GRANTED},
1347 /** Same, but opposite order. */
1348 {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1349 {{1001, 9, 1}, {1000, 10, 0}, NT_STATUS_OK},
1350 {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1351 {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1352 {{1001, 9, 2}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1353 {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1354 {{1001, 9, 3}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1356 /** Zero zero case. */
1357 {{1000, 0, 0}, {1001, 0, 0}, NT_STATUS_OK},
1360 static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1362 union smb_lock io;
1363 NTSTATUS status;
1364 bool ret = true;
1365 int fnum, i;
1366 const char *fname = BASEDIR "\\zero.txt";
1368 torture_comment(tctx, "Testing zero length byte range locks:\n");
1370 if (!torture_setup_dir(cli, BASEDIR)) {
1371 return false;
1374 io.generic.level = RAW_LOCK_LOCKX;
1376 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1377 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1378 "Failed to create %s - %s\n",
1379 fname, smbcli_errstr(cli->tree)));
1381 /* Setup initial parameters */
1382 io.lockx.level = RAW_LOCK_LOCKX;
1383 io.lockx.in.file.fnum = fnum;
1384 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1385 io.lockx.in.timeout = 0;
1387 /* Try every combination of locks in zero_byte_tests. The first lock is
1388 * assumed to succeed. The second lock may contend, depending on the
1389 * expected status. */
1390 for (i = 0;
1391 i < ARRAY_SIZE(zero_byte_tests);
1392 i++) {
1393 torture_comment(tctx, " ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1394 zero_byte_tests[i].lock1.pid,
1395 zero_byte_tests[i].lock1.offset,
1396 zero_byte_tests[i].lock1.count,
1397 zero_byte_tests[i].lock2.pid,
1398 zero_byte_tests[i].lock2.offset,
1399 zero_byte_tests[i].lock2.count,
1400 nt_errstr(zero_byte_tests[i].exp_status));
1402 /* Lock both locks. */
1403 io.lockx.in.ulock_cnt = 0;
1404 io.lockx.in.lock_cnt = 1;
1406 io.lockx.in.locks = &zero_byte_tests[i].lock1;
1407 status = smb_raw_lock(cli->tree, &io);
1408 CHECK_STATUS(status, NT_STATUS_OK);
1410 io.lockx.in.locks = &zero_byte_tests[i].lock2;
1411 status = smb_raw_lock(cli->tree, &io);
1413 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1414 NT_STATUS_LOCK_NOT_GRANTED)) {
1415 /* Allow either of the failure messages and keep going
1416 * if we see the wrong status. */
1417 CHECK_STATUS_OR_CONT(status,
1418 NT_STATUS_LOCK_NOT_GRANTED,
1419 NT_STATUS_FILE_LOCK_CONFLICT);
1421 } else {
1422 CHECK_STATUS_CONT(status,
1423 zero_byte_tests[i].exp_status);
1426 /* Unlock both locks. */
1427 io.lockx.in.ulock_cnt = 1;
1428 io.lockx.in.lock_cnt = 0;
1430 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1431 status = smb_raw_lock(cli->tree, &io);
1432 CHECK_STATUS(status, NT_STATUS_OK);
1435 io.lockx.in.locks = &zero_byte_tests[i].lock1;
1436 status = smb_raw_lock(cli->tree, &io);
1437 CHECK_STATUS(status, NT_STATUS_OK);
1440 done:
1441 smbcli_close(cli->tree, fnum);
1442 smb_raw_exit(cli->session);
1443 smbcli_deltree(cli->tree, BASEDIR);
1444 return ret;
1447 static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1449 union smb_lock io;
1450 NTSTATUS status;
1451 bool ret = true;
1452 int fnum1, fnum2;
1453 const char *fname = BASEDIR "\\unlock.txt";
1454 struct smb_lock_entry lock1;
1455 struct smb_lock_entry lock2;
1457 torture_comment(tctx, "Testing LOCKX unlock:\n");
1459 if (!torture_setup_dir(cli, BASEDIR)) {
1460 return false;
1463 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1464 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1465 "Failed to create %s - %s\n",
1466 fname, smbcli_errstr(cli->tree)));
1468 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1469 torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1470 "Failed to create %s - %s\n",
1471 fname, smbcli_errstr(cli->tree)));
1473 /* Setup initial parameters */
1474 io.lockx.level = RAW_LOCK_LOCKX;
1475 io.lockx.in.timeout = 0;
1477 lock1.pid = cli->session->pid;
1478 lock1.offset = 0;
1479 lock1.count = 10;
1480 lock2.pid = cli->session->pid - 1;
1481 lock2.offset = 0;
1482 lock2.count = 10;
1485 * Take exclusive lock, then unlock it with a shared-unlock call.
1487 torture_comment(tctx, " taking exclusive lock.\n");
1488 io.lockx.in.ulock_cnt = 0;
1489 io.lockx.in.lock_cnt = 1;
1490 io.lockx.in.mode = 0;
1491 io.lockx.in.file.fnum = fnum1;
1492 io.lockx.in.locks = &lock1;
1493 status = smb_raw_lock(cli->tree, &io);
1494 CHECK_STATUS(status, NT_STATUS_OK);
1496 torture_comment(tctx, " unlock the exclusive with a shared unlock call.\n");
1497 io.lockx.in.ulock_cnt = 1;
1498 io.lockx.in.lock_cnt = 0;
1499 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1500 io.lockx.in.file.fnum = fnum1;
1501 io.lockx.in.locks = &lock1;
1502 status = smb_raw_lock(cli->tree, &io);
1503 CHECK_STATUS(status, NT_STATUS_OK);
1505 torture_comment(tctx, " try shared lock on pid2/fnum2, testing the unlock.\n");
1506 io.lockx.in.ulock_cnt = 0;
1507 io.lockx.in.lock_cnt = 1;
1508 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1509 io.lockx.in.file.fnum = fnum2;
1510 io.lockx.in.locks = &lock2;
1511 status = smb_raw_lock(cli->tree, &io);
1512 CHECK_STATUS(status, NT_STATUS_OK);
1515 * Unlock a shared lock with an exclusive-unlock call.
1517 torture_comment(tctx, " unlock new shared lock with exclusive unlock call.\n");
1518 io.lockx.in.ulock_cnt = 1;
1519 io.lockx.in.lock_cnt = 0;
1520 io.lockx.in.mode = 0;
1521 io.lockx.in.file.fnum = fnum2;
1522 io.lockx.in.locks = &lock2;
1523 status = smb_raw_lock(cli->tree, &io);
1524 CHECK_STATUS(status, NT_STATUS_OK);
1526 torture_comment(tctx, " try exclusive lock on pid1, testing the unlock.\n");
1527 io.lockx.in.ulock_cnt = 0;
1528 io.lockx.in.lock_cnt = 1;
1529 io.lockx.in.mode = 0;
1530 io.lockx.in.file.fnum = fnum1;
1531 io.lockx.in.locks = &lock1;
1532 status = smb_raw_lock(cli->tree, &io);
1533 CHECK_STATUS(status, NT_STATUS_OK);
1535 /* cleanup */
1536 io.lockx.in.ulock_cnt = 1;
1537 io.lockx.in.lock_cnt = 0;
1538 status = smb_raw_lock(cli->tree, &io);
1539 CHECK_STATUS(status, NT_STATUS_OK);
1542 * Test unlocking of 0-byte locks.
1545 torture_comment(tctx, " lock shared and exclusive 0-byte locks, testing that Windows "
1546 "always unlocks the exclusive first.\n");
1547 lock1.pid = cli->session->pid;
1548 lock1.offset = 10;
1549 lock1.count = 0;
1550 lock2.pid = cli->session->pid;
1551 lock2.offset = 5;
1552 lock2.count = 10;
1553 io.lockx.in.ulock_cnt = 0;
1554 io.lockx.in.lock_cnt = 1;
1555 io.lockx.in.file.fnum = fnum1;
1556 io.lockx.in.locks = &lock1;
1558 /* lock 0-byte shared
1559 * Note: Order of the shared/exclusive locks doesn't matter. */
1560 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1561 status = smb_raw_lock(cli->tree, &io);
1562 CHECK_STATUS(status, NT_STATUS_OK);
1564 /* lock 0-byte exclusive */
1565 io.lockx.in.mode = 0;
1566 status = smb_raw_lock(cli->tree, &io);
1567 CHECK_STATUS(status, NT_STATUS_OK);
1569 /* test contention */
1570 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1571 io.lockx.in.locks = &lock2;
1572 io.lockx.in.file.fnum = fnum2;
1573 status = smb_raw_lock(cli->tree, &io);
1574 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1575 NT_STATUS_FILE_LOCK_CONFLICT);
1577 /* unlock */
1578 io.lockx.in.ulock_cnt = 1;
1579 io.lockx.in.lock_cnt = 0;
1580 io.lockx.in.file.fnum = fnum1;
1581 io.lockx.in.locks = &lock1;
1582 status = smb_raw_lock(cli->tree, &io);
1583 CHECK_STATUS(status, NT_STATUS_OK);
1585 /* test - can we take a shared lock? */
1586 io.lockx.in.ulock_cnt = 0;
1587 io.lockx.in.lock_cnt = 1;
1588 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1589 io.lockx.in.file.fnum = fnum2;
1590 io.lockx.in.locks = &lock2;
1591 status = smb_raw_lock(cli->tree, &io);
1593 /* XXX Samba 3 will fail this test. This is temporary(because this isn't
1594 * new to Win7, it succeeds in WinXP too), until I can come to a
1595 * resolution as to whether Samba should support this or not. There is
1596 * code to preference unlocking exclusive locks before shared locks,
1597 * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1598 if (TARGET_IS_SAMBA3(tctx)) {
1599 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1600 NT_STATUS_FILE_LOCK_CONFLICT);
1601 } else {
1602 CHECK_STATUS(status, NT_STATUS_OK);
1605 /* cleanup */
1606 io.lockx.in.ulock_cnt = 1;
1607 io.lockx.in.lock_cnt = 0;
1608 status = smb_raw_lock(cli->tree, &io);
1610 /* XXX Same as above. */
1611 if (TARGET_IS_SAMBA3(tctx)) {
1612 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1613 } else {
1614 CHECK_STATUS(status, NT_STATUS_OK);
1617 io.lockx.in.file.fnum = fnum1;
1618 io.lockx.in.locks = &lock1;
1619 status = smb_raw_lock(cli->tree, &io);
1620 CHECK_STATUS(status, NT_STATUS_OK);
1622 done:
1623 smbcli_close(cli->tree, fnum1);
1624 smbcli_close(cli->tree, fnum2);
1625 smb_raw_exit(cli->session);
1626 smbcli_deltree(cli->tree, BASEDIR);
1627 return ret;
1630 static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1632 union smb_lock io;
1633 NTSTATUS status;
1634 bool ret = true;
1635 int fnum1;
1636 const char *fname = BASEDIR "\\unlock_multiple.txt";
1637 struct smb_lock_entry lock1;
1638 struct smb_lock_entry lock2;
1639 struct smb_lock_entry locks[2];
1641 torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1643 if (!torture_setup_dir(cli, BASEDIR)) {
1644 return false;
1647 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1648 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1649 "Failed to create %s - %s\n",
1650 fname, smbcli_errstr(cli->tree)));
1652 /* Setup initial parameters */
1653 io.lockx.level = RAW_LOCK_LOCKX;
1654 io.lockx.in.timeout = 0;
1656 lock1.pid = cli->session->pid;
1657 lock1.offset = 0;
1658 lock1.count = 10;
1659 lock2.pid = cli->session->pid;
1660 lock2.offset = 10;
1661 lock2.count = 10;
1663 locks[0] = lock1;
1664 locks[1] = lock2;
1666 io.lockx.in.file.fnum = fnum1;
1667 io.lockx.in.mode = 0; /* exclusive */
1669 /** Test1: Take second lock, but not first. */
1670 torture_comment(tctx, " unlock 2 locks, first one not locked. Expect no locks "
1671 "unlocked. \n");
1673 io.lockx.in.ulock_cnt = 0;
1674 io.lockx.in.lock_cnt = 1;
1675 io.lockx.in.locks = &lock2;
1676 status = smb_raw_lock(cli->tree, &io);
1677 CHECK_STATUS(status, NT_STATUS_OK);
1679 /* Try to unlock both locks. */
1680 io.lockx.in.ulock_cnt = 2;
1681 io.lockx.in.lock_cnt = 0;
1682 io.lockx.in.locks = locks;
1684 status = smb_raw_lock(cli->tree, &io);
1685 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1687 /* Second lock should not be unlocked. */
1688 io.lockx.in.ulock_cnt = 0;
1689 io.lockx.in.lock_cnt = 1;
1690 io.lockx.in.locks = &lock2;
1691 status = smb_raw_lock(cli->tree, &io);
1692 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1694 /* cleanup */
1695 io.lockx.in.ulock_cnt = 1;
1696 io.lockx.in.lock_cnt = 0;
1697 io.lockx.in.locks = &lock2;
1698 status = smb_raw_lock(cli->tree, &io);
1699 CHECK_STATUS(status, NT_STATUS_OK);
1701 /** Test2: Take first lock, but not second. */
1702 torture_comment(tctx, " unlock 2 locks, second one not locked. Expect first lock "
1703 "unlocked.\n");
1705 io.lockx.in.ulock_cnt = 0;
1706 io.lockx.in.lock_cnt = 1;
1707 io.lockx.in.locks = &lock1;
1708 status = smb_raw_lock(cli->tree, &io);
1709 CHECK_STATUS(status, NT_STATUS_OK);
1711 /* Try to unlock both locks. */
1712 io.lockx.in.ulock_cnt = 2;
1713 io.lockx.in.lock_cnt = 0;
1714 io.lockx.in.locks = locks;
1716 status = smb_raw_lock(cli->tree, &io);
1717 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1719 /* First lock should be unlocked. */
1720 io.lockx.in.ulock_cnt = 0;
1721 io.lockx.in.lock_cnt = 1;
1722 io.lockx.in.locks = &lock1;
1723 status = smb_raw_lock(cli->tree, &io);
1724 CHECK_STATUS(status, NT_STATUS_OK);
1726 /* cleanup */
1727 io.lockx.in.ulock_cnt = 1;
1728 io.lockx.in.lock_cnt = 0;
1729 io.lockx.in.locks = &lock1;
1730 status = smb_raw_lock(cli->tree, &io);
1731 CHECK_STATUS(status, NT_STATUS_OK);
1733 done:
1734 smbcli_close(cli->tree, fnum1);
1735 smb_raw_exit(cli->session);
1736 smbcli_deltree(cli->tree, BASEDIR);
1737 return ret;
1741 * torture_locktest5 covers stacking pretty well, but its missing two tests:
1742 * - stacking an exclusive on top of shared fails
1743 * - stacking two exclusives fail
1745 static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
1747 union smb_lock io;
1748 NTSTATUS status;
1749 bool ret = true;
1750 int fnum1;
1751 const char *fname = BASEDIR "\\stacking.txt";
1752 struct smb_lock_entry lock1;
1753 struct smb_lock_entry lock2;
1755 torture_comment(tctx, "Testing stacking:\n");
1757 if (!torture_setup_dir(cli, BASEDIR)) {
1758 return false;
1761 io.generic.level = RAW_LOCK_LOCKX;
1763 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1764 torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1765 "Failed to create %s - %s\n",
1766 fname, smbcli_errstr(cli->tree)));
1768 /* Setup initial parameters */
1769 io.lockx.level = RAW_LOCK_LOCKX;
1770 io.lockx.in.timeout = 0;
1772 lock1.pid = cli->session->pid;
1773 lock1.offset = 0;
1774 lock1.count = 10;
1775 lock2.pid = cli->session->pid - 1;
1776 lock2.offset = 0;
1777 lock2.count = 10;
1780 * Try to take a shared lock, then stack an exclusive.
1782 torture_comment(tctx, " stacking an exclusive on top of a shared lock fails.\n");
1783 io.lockx.in.file.fnum = fnum1;
1784 io.lockx.in.locks = &lock1;
1786 io.lockx.in.ulock_cnt = 0;
1787 io.lockx.in.lock_cnt = 1;
1788 io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1789 status = smb_raw_lock(cli->tree, &io);
1790 CHECK_STATUS(status, NT_STATUS_OK);
1792 io.lockx.in.ulock_cnt = 0;
1793 io.lockx.in.lock_cnt = 1;
1794 io.lockx.in.mode = 0;
1795 status = smb_raw_lock(cli->tree, &io);
1796 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1797 NT_STATUS_FILE_LOCK_CONFLICT);
1799 /* cleanup */
1800 io.lockx.in.ulock_cnt = 1;
1801 io.lockx.in.lock_cnt = 0;
1802 status = smb_raw_lock(cli->tree, &io);
1803 CHECK_STATUS(status, NT_STATUS_OK);
1806 * Prove that two exclusive locks do not stack.
1808 torture_comment(tctx, " two exclusive locks do not stack.\n");
1809 io.lockx.in.ulock_cnt = 0;
1810 io.lockx.in.lock_cnt = 1;
1811 io.lockx.in.mode = 0;
1812 status = smb_raw_lock(cli->tree, &io);
1813 CHECK_STATUS(status, NT_STATUS_OK);
1814 status = smb_raw_lock(cli->tree, &io);
1815 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1816 NT_STATUS_FILE_LOCK_CONFLICT);
1818 /* cleanup */
1819 io.lockx.in.ulock_cnt = 1;
1820 io.lockx.in.lock_cnt = 0;
1821 status = smb_raw_lock(cli->tree, &io);
1822 CHECK_STATUS(status, NT_STATUS_OK);
1824 done:
1825 smbcli_close(cli->tree, fnum1);
1826 smb_raw_exit(cli->session);
1827 smbcli_deltree(cli->tree, BASEDIR);
1828 return ret;
1832 basic testing of lock calls
1834 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
1836 struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
1838 torture_suite_add_1smb_test(suite, "lockx", test_lockx);
1839 torture_suite_add_1smb_test(suite, "lock", test_lock);
1840 torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
1841 torture_suite_add_1smb_test(suite, "async", test_async);
1842 torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
1843 torture_suite_add_1smb_test(suite, "changetype", test_changetype);
1845 torture_suite_add_1smb_test(suite, "stacking", test_stacking);
1846 torture_suite_add_1smb_test(suite, "unlock", test_unlock);
1847 torture_suite_add_1smb_test(suite, "multiple_unlock",
1848 test_multiple_unlock);
1849 torture_suite_add_1smb_test(suite, "zerobytelocks",
1850 test_zerobytelocks);
1852 return suite;