s3-selftest: Remove some unnecessary comma
[Samba/gebeck_regimport.git] / source4 / torture / basic / locking.c
blob5cd6937b77bfc5a3aa4f6339720e556f3a9862b1
1 /*
2 Unix SMB/CIFS implementation.
4 basic locking tests
6 Copyright (C) Andrew Tridgell 2000-2004
7 Copyright (C) Jeremy Allison 2000-2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
26 #include "system/time.h"
27 #include "system/filesys.h"
28 #include "torture/basic/proto.h"
30 #define BASEDIR "\\locktest"
33 This test checks for two things:
35 1) correct support for retaining locks over a close (ie. the server
36 must not use posix semantics)
37 2) support for lock timeouts
39 static bool torture_locktest1(struct torture_context *tctx,
40 struct smbcli_state *cli1,
41 struct smbcli_state *cli2)
43 const char *fname = BASEDIR "\\lockt1.lck";
44 int fnum1, fnum2, fnum3;
45 time_t t1, t2;
46 unsigned int lock_timeout;
48 if (!torture_setup_dir(cli1, BASEDIR)) {
49 return false;
52 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
53 torture_assert(tctx, fnum1 != -1,
54 talloc_asprintf(tctx,
55 "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
56 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
57 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
58 "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
59 fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
60 torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx,
61 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
63 torture_assert_ntstatus_ok(tctx,
64 smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
65 talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
67 torture_assert(tctx,
68 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
69 "lock2 succeeded! This is a locking bug\n");
71 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
72 NT_STATUS_LOCK_NOT_GRANTED)) return false;
74 torture_assert(tctx,
75 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
76 "lock2 succeeded! This is a locking bug\n");
78 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
79 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
81 torture_assert_ntstatus_ok(tctx,
82 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
83 talloc_asprintf(tctx,
84 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
86 torture_assert(tctx,
87 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
88 "lock2 succeeded! This is a locking bug");
90 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
91 NT_STATUS_LOCK_NOT_GRANTED)) return false;
93 torture_assert(tctx,
94 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
95 "lock2 succeeded! This is a locking bug");
97 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
98 NT_STATUS_LOCK_NOT_GRANTED)) return false;
100 torture_assert(tctx,
101 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
102 "lock2 succeeded! This is a locking bug");
104 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
105 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
107 lock_timeout = (6 + (random() % 20));
108 torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
109 lock_timeout);
110 t1 = time_mono(NULL);
111 torture_assert(tctx,
112 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
113 "lock3 succeeded! This is a locking bug\n");
115 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
116 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
117 t2 = time_mono(NULL);
119 if (t2 - t1 < 5) {
120 torture_fail(tctx,
121 "error: This server appears not to support timed lock requests");
123 torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
124 (unsigned int)(t2-t1), lock_timeout);
126 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
127 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
129 torture_assert(tctx,
130 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
131 "lock4 succeeded! This is a locking bug");
133 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
134 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
136 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
137 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
139 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
140 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
142 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
143 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
145 return true;
150 This test checks that
152 1) the server supports multiple locking contexts on the one SMB
153 connection, distinguished by PID.
155 2) the server correctly fails overlapping locks made by the same PID (this
156 goes against POSIX behaviour, which is why it is tricky to implement)
158 3) the server denies unlock requests by an incorrect client PID
160 static bool torture_locktest2(struct torture_context *tctx,
161 struct smbcli_state *cli)
163 const char *fname = BASEDIR "\\lockt2.lck";
164 int fnum1, fnum2, fnum3;
166 if (!torture_setup_dir(cli, BASEDIR)) {
167 return false;
170 torture_comment(tctx, "Testing pid context\n");
172 cli->session->pid = 1;
174 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
175 torture_assert(tctx, fnum1 != -1,
176 talloc_asprintf(tctx,
177 "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
179 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
180 torture_assert(tctx, fnum2 != -1,
181 talloc_asprintf(tctx, "open2 of %s failed (%s)",
182 fname, smbcli_errstr(cli->tree)));
184 cli->session->pid = 2;
186 fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
187 torture_assert(tctx, fnum3 != -1,
188 talloc_asprintf(tctx,
189 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
191 cli->session->pid = 1;
193 torture_assert_ntstatus_ok(tctx,
194 smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
195 talloc_asprintf(tctx,
196 "lock1 failed (%s)", smbcli_errstr(cli->tree)));
198 torture_assert(tctx,
199 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
200 "WRITE lock1 succeeded! This is a locking bug");
202 if (!check_error(__location__, cli, ERRDOS, ERRlock,
203 NT_STATUS_LOCK_NOT_GRANTED)) return false;
205 torture_assert(tctx,
206 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
207 "WRITE lock2 succeeded! This is a locking bug");
209 if (!check_error(__location__, cli, ERRDOS, ERRlock,
210 NT_STATUS_LOCK_NOT_GRANTED)) return false;
212 torture_assert(tctx,
213 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
214 "READ lock2 succeeded! This is a locking bug");
216 if (!check_error(__location__, cli, ERRDOS, ERRlock,
217 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
219 torture_assert_ntstatus_ok(tctx,
220 smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
221 talloc_asprintf(tctx,
222 "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
224 cli->session->pid = 2;
226 torture_assert(tctx,
227 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
228 "unlock at 100 succeeded! This is a locking bug");
230 torture_assert(tctx,
231 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
232 "unlock1 succeeded! This is a locking bug");
234 if (!check_error(__location__, cli,
235 ERRDOS, ERRnotlocked,
236 NT_STATUS_RANGE_NOT_LOCKED)) return false;
238 torture_assert(tctx,
239 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
240 "unlock2 succeeded! This is a locking bug");
242 if (!check_error(__location__, cli,
243 ERRDOS, ERRnotlocked,
244 NT_STATUS_RANGE_NOT_LOCKED)) return false;
246 torture_assert(tctx,
247 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
248 "lock3 succeeded! This is a locking bug");
250 if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
252 cli->session->pid = 1;
254 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
255 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
257 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
258 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
260 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
261 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
263 return true;
268 This test checks that
270 1) the server supports the full offset range in lock requests
272 static bool torture_locktest3(struct torture_context *tctx,
273 struct smbcli_state *cli1,
274 struct smbcli_state *cli2)
276 const char *fname = BASEDIR "\\lockt3.lck";
277 int fnum1, fnum2, i;
278 uint32_t offset;
279 extern int torture_numops;
281 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
283 torture_comment(tctx, "Testing 32 bit offset ranges");
285 if (!torture_setup_dir(cli1, BASEDIR)) {
286 return false;
289 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
290 torture_assert(tctx, fnum1 != -1,
291 talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
292 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
293 torture_assert(tctx, fnum2 != -1,
294 talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
296 torture_comment(tctx, "Establishing %d locks\n", torture_numops);
298 for (offset=i=0;i<torture_numops;i++) {
299 NEXT_OFFSET;
300 torture_assert_ntstatus_ok(tctx,
301 smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
302 talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
304 torture_assert_ntstatus_ok(tctx,
305 smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
306 talloc_asprintf(tctx, "lock2 %d failed (%s)",
307 i, smbcli_errstr(cli1->tree)));
310 torture_comment(tctx, "Testing %d locks\n", torture_numops);
312 for (offset=i=0;i<torture_numops;i++) {
313 NEXT_OFFSET;
315 torture_assert(tctx,
316 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
317 talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
319 torture_assert(tctx,
320 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
321 talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
323 torture_assert(tctx,
324 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
325 talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
327 torture_assert(tctx,
328 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
329 talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
332 torture_comment(tctx, "Removing %d locks\n", torture_numops);
334 for (offset=i=0;i<torture_numops;i++) {
335 NEXT_OFFSET;
337 torture_assert_ntstatus_ok(tctx,
338 smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
339 talloc_asprintf(tctx, "unlock1 %d failed (%s)",
341 smbcli_errstr(cli1->tree)));
343 torture_assert_ntstatus_ok(tctx,
344 smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
345 talloc_asprintf(tctx, "unlock2 %d failed (%s)",
347 smbcli_errstr(cli1->tree)));
350 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
351 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
353 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
354 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
356 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
357 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
359 return true;
362 #define EXPECTED(ret, v) if ((ret) != (v)) { \
363 torture_comment(tctx, "** "); correct = false; \
367 looks at overlapping locks
369 static bool torture_locktest4(struct torture_context *tctx,
370 struct smbcli_state *cli1,
371 struct smbcli_state *cli2)
373 const char *fname = BASEDIR "\\lockt4.lck";
374 int fnum1, fnum2, f;
375 bool ret;
376 uint8_t buf[1000];
377 bool correct = true;
379 if (!torture_setup_dir(cli1, BASEDIR)) {
380 return false;
383 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
384 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
386 memset(buf, 0, sizeof(buf));
388 if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
389 torture_comment(tctx, "Failed to create file\n");
390 correct = false;
391 goto fail;
394 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
395 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
396 EXPECTED(ret, false);
397 torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
399 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
400 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
401 EXPECTED(ret, true);
402 torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
404 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
405 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
406 EXPECTED(ret, false);
407 torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
409 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
410 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
411 EXPECTED(ret, true);
412 torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
414 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
415 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
416 EXPECTED(ret, false);
417 torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
419 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
420 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
421 EXPECTED(ret, true);
422 torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
424 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
425 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
426 EXPECTED(ret, true);
427 torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
429 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
430 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
431 EXPECTED(ret, false);
432 torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
434 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
435 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
436 EXPECTED(ret, false);
437 torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
439 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
440 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
441 EXPECTED(ret, true);
442 torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
444 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
445 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
446 EXPECTED(ret, false);
447 torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
449 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
450 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
451 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
452 EXPECTED(ret, false);
453 torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
456 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
457 (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
458 EXPECTED(ret, false);
459 torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
461 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
462 (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
463 EXPECTED(ret, false);
464 torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
467 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
468 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
469 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
470 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
471 EXPECTED(ret, true);
472 torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
475 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
476 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
477 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
478 (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
479 !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
480 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
481 EXPECTED(ret, true);
482 torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
484 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
485 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
486 (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&
487 (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);
488 EXPECTED(ret, true);
489 torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
491 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
492 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
493 (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&
494 (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);
495 EXPECTED(ret, true);
496 torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
498 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
499 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
500 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
501 !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&
502 (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);
503 EXPECTED(ret, true);
504 torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
506 smbcli_close(cli1->tree, fnum1);
507 smbcli_close(cli2->tree, fnum2);
508 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
509 f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
510 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
511 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
512 NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
513 ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
514 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
515 smbcli_close(cli1->tree, f);
516 smbcli_close(cli1->tree, fnum1);
517 EXPECTED(ret, true);
518 torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
520 fail:
521 smbcli_close(cli1->tree, fnum1);
522 smbcli_close(cli2->tree, fnum2);
523 smbcli_unlink(cli1->tree, fname);
525 return correct;
529 looks at lock upgrade/downgrade.
531 static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
532 struct smbcli_state *cli2)
534 const char *fname = BASEDIR "\\lockt5.lck";
535 int fnum1, fnum2, fnum3;
536 bool ret;
537 uint8_t buf[1000];
538 bool correct = true;
540 if (!torture_setup_dir(cli1, BASEDIR)) {
541 return false;
544 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
545 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
546 fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
548 memset(buf, 0, sizeof(buf));
550 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
551 "Failed to create file");
553 /* Check for NT bug... */
554 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
555 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
556 smbcli_close(cli1->tree, fnum1);
557 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
558 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
559 EXPECTED(ret, true);
560 torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
561 smbcli_close(cli1->tree, fnum1);
562 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
563 smbcli_unlock(cli1->tree, fnum3, 0, 1);
565 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
566 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
567 EXPECTED(ret, true);
568 torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
570 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
571 EXPECTED(ret, false);
573 torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
575 /* Unlock the process 2 lock. */
576 smbcli_unlock(cli2->tree, fnum2, 0, 4);
578 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
579 EXPECTED(ret, false);
581 torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
583 /* Unlock the process 1 fnum3 lock. */
584 smbcli_unlock(cli1->tree, fnum3, 0, 4);
586 /* Stack 2 more locks here. */
587 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
588 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
590 EXPECTED(ret, true);
591 torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
593 /* Unlock the first process lock, then check this was the WRITE lock that was
594 removed. */
596 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
597 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
599 EXPECTED(ret, true);
600 torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
602 /* Unlock the process 2 lock. */
603 smbcli_unlock(cli2->tree, fnum2, 0, 4);
605 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
607 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
608 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
609 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
611 EXPECTED(ret, true);
612 torture_comment(tctx, "the same process %s unlock the stack of 3 locks\n", ret?"can":"cannot");
614 /* Ensure the next unlock fails. */
615 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
616 EXPECTED(ret, false);
617 torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot");
619 /* Ensure connection 2 can get a write lock. */
620 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
621 EXPECTED(ret, true);
623 torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
626 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
627 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
629 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
630 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
632 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
633 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
635 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
636 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
638 return correct;
642 tries the unusual lockingX locktype bits
644 static bool torture_locktest6(struct torture_context *tctx,
645 struct smbcli_state *cli)
647 const char *fname[1] = { "\\lock6.txt" };
648 int i;
649 int fnum;
650 NTSTATUS status;
652 if (!torture_setup_dir(cli, BASEDIR)) {
653 return false;
656 for (i=0;i<1;i++) {
657 torture_comment(tctx, "Testing %s\n", fname[i]);
659 smbcli_unlink(cli->tree, fname[i]);
661 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
662 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
663 smbcli_close(cli->tree, fnum);
664 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
666 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
667 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
668 smbcli_close(cli->tree, fnum);
669 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
671 smbcli_unlink(cli->tree, fname[i]);
674 return true;
677 static bool torture_locktest7(struct torture_context *tctx,
678 struct smbcli_state *cli1)
680 const char *fname = BASEDIR "\\lockt7.lck";
681 int fnum1;
682 int fnum2 = -1;
683 size_t size;
684 uint8_t buf[200];
685 bool correct = false;
687 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
688 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
690 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
692 memset(buf, 0, sizeof(buf));
694 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
695 "Failed to create file");
697 cli1->session->pid = 1;
699 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
700 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
701 smbcli_errstr(cli1->tree)));
703 torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
705 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
706 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
707 smbcli_errstr(cli1->tree)));
709 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
711 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
712 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
713 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
714 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
715 } else {
716 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
719 cli1->session->pid = 2;
721 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
722 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
723 } else {
724 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
727 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
728 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
729 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
730 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
731 } else {
732 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
735 cli1->session->pid = 1;
736 smbcli_unlock(cli1->tree, fnum1, 130, 4);
738 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
739 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
740 smbcli_errstr(cli1->tree)));
741 torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
743 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
744 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
745 smbcli_errstr(cli1->tree)));
746 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
748 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
749 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
750 smbcli_errstr(cli1->tree)));
751 torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
753 cli1->session->pid = 2;
755 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
756 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
757 smbcli_errstr(cli1->tree));
758 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
759 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
760 } else {
761 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
764 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
765 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
766 smbcli_errstr(cli1->tree));
767 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
768 torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
769 __location__);
770 goto fail;
772 } else {
773 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
774 __location__);
775 goto fail;
778 torture_comment(tctx, "Testing truncate of locked file.\n");
780 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
782 torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
784 torture_comment(tctx, "Truncated locked file.\n");
786 torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
787 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
789 torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
791 cli1->session->pid = 1;
793 smbcli_unlock(cli1->tree, fnum1, 130, 4);
794 correct = true;
796 fail:
797 smbcli_close(cli1->tree, fnum1);
798 smbcli_close(cli1->tree, fnum2);
799 smbcli_unlink(cli1->tree, fname);
801 return correct;
804 struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
806 struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
807 torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
808 torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
809 torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
810 torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
811 torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
812 torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
813 torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);
815 return suite;