s3:winbindd: s/struct event_context/struct tevent_context
[Samba/gebeck_regimport.git] / source4 / torture / basic / locking.c
blob98def5c09c185b1d5e1b08077a99b0791dd14952
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 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
49 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
51 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
52 torture_assert(tctx, fnum1 != -1,
53 talloc_asprintf(tctx,
54 "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
55 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
56 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
57 "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
58 fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
59 torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx,
60 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
62 torture_assert_ntstatus_ok(tctx,
63 smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
64 talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
66 torture_assert(tctx,
67 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
68 "lock2 succeeded! This is a locking bug\n");
70 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
71 NT_STATUS_LOCK_NOT_GRANTED)) return false;
73 torture_assert(tctx,
74 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
75 "lock2 succeeded! This is a locking bug\n");
77 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
78 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
80 torture_assert_ntstatus_ok(tctx,
81 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
82 talloc_asprintf(tctx,
83 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
85 torture_assert(tctx,
86 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
87 "lock2 succeeded! This is a locking bug");
89 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
90 NT_STATUS_LOCK_NOT_GRANTED)) return false;
92 torture_assert(tctx,
93 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
94 "lock2 succeeded! This is a locking bug");
96 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
97 NT_STATUS_LOCK_NOT_GRANTED)) return false;
99 torture_assert(tctx,
100 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
101 "lock2 succeeded! This is a locking bug");
103 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
104 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
106 lock_timeout = (6 + (random() % 20));
107 torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
108 lock_timeout);
109 t1 = time_mono(NULL);
110 torture_assert(tctx,
111 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
112 "lock3 succeeded! This is a locking bug\n");
114 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
115 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
116 t2 = time_mono(NULL);
118 if (t2 - t1 < 5) {
119 torture_fail(tctx,
120 "error: This server appears not to support timed lock requests");
122 torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
123 (unsigned int)(t2-t1), lock_timeout);
125 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
126 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
128 torture_assert(tctx,
129 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
130 "lock4 succeeded! This is a locking bug");
132 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
133 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
135 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
136 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
138 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
139 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
141 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
142 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
144 return true;
149 This test checks that
151 1) the server supports multiple locking contexts on the one SMB
152 connection, distinguished by PID.
154 2) the server correctly fails overlapping locks made by the same PID (this
155 goes against POSIX behaviour, which is why it is tricky to implement)
157 3) the server denies unlock requests by an incorrect client PID
159 static bool torture_locktest2(struct torture_context *tctx,
160 struct smbcli_state *cli)
162 const char *fname = BASEDIR "\\lockt2.lck";
163 int fnum1, fnum2, fnum3;
165 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
166 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
168 torture_comment(tctx, "Testing pid context\n");
170 cli->session->pid = 1;
172 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
173 torture_assert(tctx, fnum1 != -1,
174 talloc_asprintf(tctx,
175 "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
177 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
178 torture_assert(tctx, fnum2 != -1,
179 talloc_asprintf(tctx, "open2 of %s failed (%s)",
180 fname, smbcli_errstr(cli->tree)));
182 cli->session->pid = 2;
184 fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
185 torture_assert(tctx, fnum3 != -1,
186 talloc_asprintf(tctx,
187 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
189 cli->session->pid = 1;
191 torture_assert_ntstatus_ok(tctx,
192 smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
193 talloc_asprintf(tctx,
194 "lock1 failed (%s)", smbcli_errstr(cli->tree)));
196 torture_assert(tctx,
197 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
198 "WRITE lock1 succeeded! This is a locking bug");
200 if (!check_error(__location__, cli, ERRDOS, ERRlock,
201 NT_STATUS_LOCK_NOT_GRANTED)) return false;
203 torture_assert(tctx,
204 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
205 "WRITE lock2 succeeded! This is a locking bug");
207 if (!check_error(__location__, cli, ERRDOS, ERRlock,
208 NT_STATUS_LOCK_NOT_GRANTED)) return false;
210 torture_assert(tctx,
211 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
212 "READ lock2 succeeded! This is a locking bug");
214 if (!check_error(__location__, cli, ERRDOS, ERRlock,
215 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
217 torture_assert_ntstatus_ok(tctx,
218 smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
219 talloc_asprintf(tctx,
220 "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
222 cli->session->pid = 2;
224 torture_assert(tctx,
225 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
226 "unlock at 100 succeeded! This is a locking bug");
228 torture_assert(tctx,
229 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
230 "unlock1 succeeded! This is a locking bug");
232 if (!check_error(__location__, cli,
233 ERRDOS, ERRnotlocked,
234 NT_STATUS_RANGE_NOT_LOCKED)) return false;
236 torture_assert(tctx,
237 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
238 "unlock2 succeeded! This is a locking bug");
240 if (!check_error(__location__, cli,
241 ERRDOS, ERRnotlocked,
242 NT_STATUS_RANGE_NOT_LOCKED)) return false;
244 torture_assert(tctx,
245 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
246 "lock3 succeeded! This is a locking bug");
248 if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
250 cli->session->pid = 1;
252 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
253 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
255 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
256 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
258 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
259 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
261 return true;
266 This test checks that
268 1) the server supports the full offset range in lock requests
270 static bool torture_locktest3(struct torture_context *tctx,
271 struct smbcli_state *cli1,
272 struct smbcli_state *cli2)
274 const char *fname = BASEDIR "\\lockt3.lck";
275 int fnum1, fnum2, i;
276 uint32_t offset;
277 extern int torture_numops;
279 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
281 torture_comment(tctx, "Testing 32 bit offset ranges");
283 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
284 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
286 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
287 torture_assert(tctx, fnum1 != -1,
288 talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
289 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
290 torture_assert(tctx, fnum2 != -1,
291 talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
293 torture_comment(tctx, "Establishing %d locks\n", torture_numops);
295 for (offset=i=0;i<torture_numops;i++) {
296 NEXT_OFFSET;
297 torture_assert_ntstatus_ok(tctx,
298 smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
299 talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
301 torture_assert_ntstatus_ok(tctx,
302 smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
303 talloc_asprintf(tctx, "lock2 %d failed (%s)",
304 i, smbcli_errstr(cli1->tree)));
307 torture_comment(tctx, "Testing %d locks\n", torture_numops);
309 for (offset=i=0;i<torture_numops;i++) {
310 NEXT_OFFSET;
312 torture_assert(tctx,
313 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
314 talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
316 torture_assert(tctx,
317 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
318 talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
320 torture_assert(tctx,
321 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
322 talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
324 torture_assert(tctx,
325 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
326 talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
329 torture_comment(tctx, "Removing %d locks\n", torture_numops);
331 for (offset=i=0;i<torture_numops;i++) {
332 NEXT_OFFSET;
334 torture_assert_ntstatus_ok(tctx,
335 smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
336 talloc_asprintf(tctx, "unlock1 %d failed (%s)",
338 smbcli_errstr(cli1->tree)));
340 torture_assert_ntstatus_ok(tctx,
341 smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
342 talloc_asprintf(tctx, "unlock2 %d failed (%s)",
344 smbcli_errstr(cli1->tree)));
347 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
348 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
350 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
351 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
353 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
354 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
356 return true;
359 #define EXPECTED(ret, v) if ((ret) != (v)) { \
360 torture_comment(tctx, "** "); correct = false; \
364 looks at overlapping locks
366 static bool torture_locktest4(struct torture_context *tctx,
367 struct smbcli_state *cli1,
368 struct smbcli_state *cli2)
370 const char *fname = BASEDIR "\\lockt4.lck";
371 int fnum1, fnum2, f;
372 bool ret;
373 uint8_t buf[1000];
374 bool correct = true;
376 if (!torture_setup_dir(cli1, BASEDIR)) {
377 return false;
380 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
381 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
383 memset(buf, 0, sizeof(buf));
385 if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
386 torture_comment(tctx, "Failed to create file\n");
387 correct = false;
388 goto fail;
391 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
392 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
393 EXPECTED(ret, false);
394 torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
396 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
397 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
398 EXPECTED(ret, true);
399 torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
401 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
402 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
403 EXPECTED(ret, false);
404 torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
406 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
407 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
408 EXPECTED(ret, true);
409 torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
411 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
412 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
413 EXPECTED(ret, false);
414 torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
416 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
417 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
418 EXPECTED(ret, true);
419 torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
421 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
422 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
423 EXPECTED(ret, true);
424 torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
426 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
427 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
428 EXPECTED(ret, false);
429 torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
431 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
432 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
433 EXPECTED(ret, false);
434 torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
436 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
437 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
438 EXPECTED(ret, true);
439 torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
441 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
442 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
443 EXPECTED(ret, false);
444 torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
446 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
447 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
448 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
449 EXPECTED(ret, false);
450 torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
453 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
454 (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
455 EXPECTED(ret, false);
456 torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
458 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
459 (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
460 EXPECTED(ret, false);
461 torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
464 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
465 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
466 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
467 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
468 EXPECTED(ret, true);
469 torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
472 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
473 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
474 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
475 (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
476 !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
477 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
478 EXPECTED(ret, true);
479 torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
481 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
482 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
483 (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&
484 (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);
485 EXPECTED(ret, true);
486 torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
488 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
489 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
490 (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&
491 (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);
492 EXPECTED(ret, true);
493 torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
495 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
496 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
497 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
498 !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&
499 (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);
500 EXPECTED(ret, true);
501 torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
503 smbcli_close(cli1->tree, fnum1);
504 smbcli_close(cli2->tree, fnum2);
505 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
506 f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
507 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
508 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
509 NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
510 ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
511 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
512 smbcli_close(cli1->tree, f);
513 smbcli_close(cli1->tree, fnum1);
514 EXPECTED(ret, true);
515 torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
517 fail:
518 smbcli_close(cli1->tree, fnum1);
519 smbcli_close(cli2->tree, fnum2);
520 smbcli_unlink(cli1->tree, fname);
522 return correct;
526 looks at lock upgrade/downgrade.
528 static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
529 struct smbcli_state *cli2)
531 const char *fname = BASEDIR "\\lockt5.lck";
532 int fnum1, fnum2, fnum3;
533 bool ret;
534 uint8_t buf[1000];
535 bool correct = true;
537 if (!torture_setup_dir(cli1, BASEDIR)) {
538 return false;
541 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
542 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
543 fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
545 memset(buf, 0, sizeof(buf));
547 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
548 "Failed to create file");
550 /* Check for NT bug... */
551 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
552 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
553 smbcli_close(cli1->tree, fnum1);
554 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
555 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
556 EXPECTED(ret, true);
557 torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
558 smbcli_close(cli1->tree, fnum1);
559 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
560 smbcli_unlock(cli1->tree, fnum3, 0, 1);
562 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
563 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
564 EXPECTED(ret, true);
565 torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
567 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
568 EXPECTED(ret, false);
570 torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
572 /* Unlock the process 2 lock. */
573 smbcli_unlock(cli2->tree, fnum2, 0, 4);
575 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
576 EXPECTED(ret, false);
578 torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
580 /* Unlock the process 1 fnum3 lock. */
581 smbcli_unlock(cli1->tree, fnum3, 0, 4);
583 /* Stack 2 more locks here. */
584 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
585 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
587 EXPECTED(ret, true);
588 torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
590 /* Unlock the first process lock, then check this was the WRITE lock that was
591 removed. */
593 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
594 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
596 EXPECTED(ret, true);
597 torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
599 /* Unlock the process 2 lock. */
600 smbcli_unlock(cli2->tree, fnum2, 0, 4);
602 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
604 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
605 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
606 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
608 EXPECTED(ret, true);
609 torture_comment(tctx, "the same process %s unlock the stack of 3 locks\n", ret?"can":"cannot");
611 /* Ensure the next unlock fails. */
612 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
613 EXPECTED(ret, false);
614 torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot");
616 /* Ensure connection 2 can get a write lock. */
617 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
618 EXPECTED(ret, true);
620 torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
623 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
624 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
626 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
627 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
629 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
630 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
632 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
633 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
635 return correct;
639 tries the unusual lockingX locktype bits
641 static bool torture_locktest6(struct torture_context *tctx,
642 struct smbcli_state *cli)
644 const char *fname[1] = { "\\lock6.txt" };
645 int i;
646 int fnum;
647 NTSTATUS status;
649 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
651 for (i=0;i<1;i++) {
652 torture_comment(tctx, "Testing %s\n", fname[i]);
654 smbcli_unlink(cli->tree, fname[i]);
656 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
657 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
658 smbcli_close(cli->tree, fnum);
659 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
661 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
662 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
663 smbcli_close(cli->tree, fnum);
664 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
666 smbcli_unlink(cli->tree, fname[i]);
669 return true;
672 static bool torture_locktest7(struct torture_context *tctx,
673 struct smbcli_state *cli1)
675 const char *fname = BASEDIR "\\lockt7.lck";
676 int fnum1;
677 int fnum2 = -1;
678 size_t size;
679 uint8_t buf[200];
680 bool correct = false;
682 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
683 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
685 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
687 memset(buf, 0, sizeof(buf));
689 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
690 "Failed to create file");
692 cli1->session->pid = 1;
694 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
695 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
696 smbcli_errstr(cli1->tree)));
698 torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
700 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
701 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
702 smbcli_errstr(cli1->tree)));
704 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
706 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
707 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
708 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
709 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
710 } else {
711 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
714 cli1->session->pid = 2;
716 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
717 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
718 } else {
719 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
722 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
723 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
724 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
725 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
726 } else {
727 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
730 cli1->session->pid = 1;
731 smbcli_unlock(cli1->tree, fnum1, 130, 4);
733 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
734 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
735 smbcli_errstr(cli1->tree)));
736 torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
738 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
739 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
740 smbcli_errstr(cli1->tree)));
741 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
743 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
744 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
745 smbcli_errstr(cli1->tree)));
746 torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
748 cli1->session->pid = 2;
750 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
751 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
752 smbcli_errstr(cli1->tree));
753 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
754 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
755 } else {
756 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
759 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
760 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
761 smbcli_errstr(cli1->tree));
762 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
763 torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
764 __location__);
765 goto fail;
767 } else {
768 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
769 __location__);
770 goto fail;
773 torture_comment(tctx, "Testing truncate of locked file.\n");
775 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
777 torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
779 torture_comment(tctx, "Truncated locked file.\n");
781 torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
782 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
784 torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
786 cli1->session->pid = 1;
788 smbcli_unlock(cli1->tree, fnum1, 130, 4);
789 correct = true;
791 fail:
792 smbcli_close(cli1->tree, fnum1);
793 smbcli_close(cli1->tree, fnum2);
794 smbcli_unlink(cli1->tree, fname);
796 return correct;
799 struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
801 struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
802 torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
803 torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
804 torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
805 torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
806 torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
807 torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
808 torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);
810 return suite;