Add an entry for the "check" command to the tdbtool manpage.
[Samba/gebeck_regimport.git] / source4 / torture / basic / delete.c
blobc1ac62f1b1eac34cc4cbdb2b4090045977b5a77b
1 /*
2 Unix SMB/CIFS implementation.
4 delete on close testing
6 Copyright (C) Andrew Tridgell 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "libcli/libcli.h"
24 #include "torture/torture.h"
25 #include "torture/util.h"
26 #include "system/filesys.h"
27 #include "libcli/raw/libcliraw.h"
28 #include "libcli/raw/raw_proto.h"
30 #include "torture/raw/proto.h"
32 static bool check_delete_on_close(struct torture_context *tctx,
33 struct smbcli_state *cli, int fnum,
34 const char *fname, bool expect_it,
35 const char *where)
37 union smb_search_data data;
38 NTSTATUS status;
40 time_t c_time, a_time, m_time;
41 size_t size;
42 uint16_t mode;
44 status = torture_single_search(cli, tctx,
45 fname,
46 RAW_SEARCH_TRANS2,
47 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
48 FILE_ATTRIBUTE_DIRECTORY,
49 &data);
50 torture_assert_ntstatus_ok(tctx, status,
51 talloc_asprintf(tctx, "single_search failed (%s)", where));
53 if (fnum != -1) {
54 union smb_fileinfo io;
55 int nlink = expect_it ? 0 : 1;
57 io.all_info.level = RAW_FILEINFO_ALL_INFO;
58 io.all_info.in.file.fnum = fnum;
60 status = smb_raw_fileinfo(cli->tree, tctx, &io);
61 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx,
62 "qfileinfo failed (%s)", where));
64 torture_assert(tctx, expect_it == io.all_info.out.delete_pending,
65 talloc_asprintf(tctx,
66 "%s - Expected del_on_close flag %d, qfileinfo/all_info gave %d",
67 where, expect_it, io.all_info.out.delete_pending));
69 torture_assert(tctx, nlink == io.all_info.out.nlink,
70 talloc_asprintf(tctx,
71 "%s - Expected nlink %d, qfileinfo/all_info gave %d",
72 where, nlink, io.all_info.out.nlink));
74 io.standard_info.level = RAW_FILEINFO_STANDARD_INFO;
75 io.standard_info.in.file.fnum = fnum;
77 status = smb_raw_fileinfo(cli->tree, tctx, &io);
78 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
80 torture_assert(tctx, expect_it == io.standard_info.out.delete_pending,
81 talloc_asprintf(tctx, "%s - Expected del_on_close flag %d, qfileinfo/standard_info gave %d\n",
82 where, expect_it, io.standard_info.out.delete_pending));
84 torture_assert(tctx, nlink == io.standard_info.out.nlink,
85 talloc_asprintf(tctx, "%s - Expected nlink %d, qfileinfo/standard_info gave %d",
86 where, nlink, io.all_info.out.nlink));
89 status = smbcli_qpathinfo(cli->tree, fname,
90 &c_time, &a_time, &m_time,
91 &size, &mode);
93 if (expect_it) {
94 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
95 "qpathinfo did not give correct error code");
96 } else {
97 torture_assert_ntstatus_ok(tctx, status,
98 talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
101 return true;
104 #define CHECK_STATUS(_cli, _expected) \
105 torture_assert_ntstatus_equal(tctx, _cli->tree->session->transport->error.e.nt_status, _expected, \
106 "Incorrect status")
108 static const char *fname = "\\delete.file";
109 static const char *fname_new = "\\delete.new";
110 static const char *dname = "\\delete.dir";
112 static void del_clean_area(struct smbcli_state *cli1, struct smbcli_state *cli2)
114 smb_raw_exit(cli1->session);
115 smb_raw_exit(cli2->session);
117 smbcli_deltree(cli1->tree, dname);
118 smbcli_setatr(cli1->tree, fname, 0, 0);
119 smbcli_unlink(cli1->tree, fname);
120 smbcli_setatr(cli1->tree, fname_new, 0, 0);
121 smbcli_unlink(cli1->tree, fname_new);
124 /* Test 1 - this should delete the file on close. */
126 static bool deltest1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
128 int fnum1 = -1;
130 del_clean_area(cli1, cli2);
132 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
133 SEC_RIGHTS_FILE_ALL,
134 FILE_ATTRIBUTE_NORMAL,
135 NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OVERWRITE_IF,
136 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
138 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
139 fname, smbcli_errstr(cli1->tree)));
141 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
142 talloc_asprintf(tctx, "close failed (%s)", smbcli_errstr(cli1->tree)));
144 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
145 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
146 fname));
148 return true;
151 /* Test 2 - this should delete the file on close. */
152 static bool deltest2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
154 int fnum1 = -1;
156 del_clean_area(cli1, cli2);
158 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
159 SEC_RIGHTS_FILE_ALL,
160 FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
161 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
163 torture_assert(tctx, fnum1 != -1,
164 talloc_asprintf(tctx, "open of %s failed (%s)",
165 fname, smbcli_errstr(cli1->tree)));
167 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
168 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
169 smbcli_errstr(cli1->tree)));
171 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
172 talloc_asprintf(tctx, "close failed (%s)",
173 smbcli_errstr(cli1->tree)));
175 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
176 if (fnum1 != -1) {
177 printf("(%s) open of %s succeeded should have been deleted on close !\n",
178 __location__, fname);
179 if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
180 printf("(%s) close failed (%s)\n",
181 __location__, smbcli_errstr(cli1->tree));
182 return false;
184 smbcli_unlink(cli1->tree, fname);
186 return true;
189 /* Test 3 - ... */
190 static bool deltest3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
192 int fnum1 = -1;
193 int fnum2 = -1;
195 del_clean_area(cli1, cli2);
197 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
198 SEC_RIGHTS_FILE_ALL,
199 FILE_ATTRIBUTE_NORMAL,
200 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
201 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
203 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
204 fname, smbcli_errstr(cli1->tree)));
206 /* This should fail with a sharing violation - open for delete is only compatible
207 with SHARE_DELETE. */
209 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
210 SEC_RIGHTS_FILE_READ,
211 FILE_ATTRIBUTE_NORMAL,
212 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
213 NTCREATEX_DISP_OPEN, 0, 0);
215 torture_assert(tctx, fnum2 == -1,
216 talloc_asprintf(tctx, "open - 2 of %s succeeded - should have failed.",
217 fname));
219 /* This should succeed. */
221 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
222 SEC_RIGHTS_FILE_READ,
223 FILE_ATTRIBUTE_NORMAL,
224 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
225 NTCREATEX_DISP_OPEN, 0, 0);
227 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
228 fname, smbcli_errstr(cli1->tree)));
230 torture_assert_ntstatus_ok(tctx,
231 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
232 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
233 smbcli_errstr(cli1->tree)));
235 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
236 talloc_asprintf(tctx, "close 1 failed (%s)",
237 smbcli_errstr(cli1->tree)));
239 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
240 talloc_asprintf(tctx, "close 2 failed (%s)",
241 smbcli_errstr(cli1->tree)));
243 /* This should fail - file should no longer be there. */
245 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
246 if (fnum1 != -1) {
247 printf("(%s) open of %s succeeded should have been deleted on close !\n",
248 __location__, fname);
249 if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
250 printf("(%s) close failed (%s)\n",
251 __location__, smbcli_errstr(cli1->tree));
253 smbcli_unlink(cli1->tree, fname);
254 return false;
256 return true;
259 /* Test 4 ... */
260 static bool deltest4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
262 int fnum1 = -1;
263 int fnum2 = -1;
264 bool correct = true;
266 del_clean_area(cli1, cli2);
268 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
269 SEC_FILE_READ_DATA |
270 SEC_FILE_WRITE_DATA |
271 SEC_STD_DELETE,
272 FILE_ATTRIBUTE_NORMAL,
273 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
274 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
276 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
277 fname, smbcli_errstr(cli1->tree)));
279 /* This should succeed. */
280 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
281 SEC_RIGHTS_FILE_READ,
282 FILE_ATTRIBUTE_NORMAL,
283 NTCREATEX_SHARE_ACCESS_READ |
284 NTCREATEX_SHARE_ACCESS_WRITE |
285 NTCREATEX_SHARE_ACCESS_DELETE,
286 NTCREATEX_DISP_OPEN, 0, 0);
287 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
288 fname, smbcli_errstr(cli1->tree)));
290 torture_assert_ntstatus_ok(tctx,
291 smbcli_close(cli1->tree, fnum2),
292 talloc_asprintf(tctx, "close - 1 failed (%s)",
293 smbcli_errstr(cli1->tree)));
295 torture_assert_ntstatus_ok(tctx,
296 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
297 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
298 smbcli_errstr(cli1->tree)));
300 /* This should fail - no more opens once delete on close set. */
301 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
302 SEC_RIGHTS_FILE_READ,
303 FILE_ATTRIBUTE_NORMAL,
304 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
305 NTCREATEX_DISP_OPEN, 0, 0);
306 torture_assert(tctx, fnum2 == -1,
307 talloc_asprintf(tctx, "open - 3 of %s succeeded ! Should have failed.",
308 fname ));
310 CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
312 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
313 talloc_asprintf(tctx, "close - 2 failed (%s)",
314 smbcli_errstr(cli1->tree)));
316 return correct;
319 /* Test 5 ... */
320 static bool deltest5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
322 int fnum1 = -1;
324 del_clean_area(cli1, cli2);
326 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
327 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
328 fname, smbcli_errstr(cli1->tree)));
330 /* This should fail - only allowed on NT opens with DELETE access. */
332 torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
333 "setting delete_on_close on OpenX file succeeded - should fail !");
335 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
336 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
338 return true;
341 /* Test 6 ... */
342 static bool deltest6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
344 int fnum1 = -1;
346 del_clean_area(cli1, cli2);
348 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
349 SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
350 FILE_ATTRIBUTE_NORMAL,
351 NTCREATEX_SHARE_ACCESS_READ |
352 NTCREATEX_SHARE_ACCESS_WRITE |
353 NTCREATEX_SHARE_ACCESS_DELETE,
354 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
356 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
357 fname, smbcli_errstr(cli1->tree)));
359 /* This should fail - only allowed on NT opens with DELETE access. */
361 torture_assert(tctx,
362 !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
363 "setting delete_on_close on file with no delete access succeeded - should fail !");
365 torture_assert_ntstatus_ok(tctx,
366 smbcli_close(cli1->tree, fnum1),
367 talloc_asprintf(tctx, "close - 2 failed (%s)",
368 smbcli_errstr(cli1->tree)));
370 return true;
373 /* Test 7 ... */
374 static bool deltest7(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
376 int fnum1 = -1;
377 bool correct = true;
379 del_clean_area(cli1, cli2);
381 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
382 SEC_FILE_READ_DATA |
383 SEC_FILE_WRITE_DATA |
384 SEC_STD_DELETE,
385 FILE_ATTRIBUTE_NORMAL, 0,
386 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
388 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
389 fname, smbcli_errstr(cli1->tree)));
391 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
392 "setting delete_on_close on file failed !");
394 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
396 torture_assert_ntstatus_ok(tctx,
397 smbcli_nt_delete_on_close(cli1->tree, fnum1, false),
398 "unsetting delete_on_close on file failed !");
400 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
402 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
403 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
405 /* This next open should succeed - we reset the flag. */
407 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
408 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
409 fname, smbcli_errstr(cli1->tree)));
411 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
412 talloc_asprintf(tctx, "close - 2 failed (%s)",
413 smbcli_errstr(cli1->tree)));
415 return correct;
418 /* Test 8 ... */
419 static bool deltest8(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
421 int fnum1 = -1;
422 int fnum2 = -1;
423 bool correct = true;
425 del_clean_area(cli1, cli2);
427 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
428 SEC_FILE_READ_DATA|
429 SEC_FILE_WRITE_DATA|
430 SEC_STD_DELETE,
431 FILE_ATTRIBUTE_NORMAL,
432 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
433 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
435 torture_assert(tctx, fnum1 != -1,
436 talloc_asprintf(tctx, "open of %s failed (%s)",
437 fname, smbcli_errstr(cli1->tree)));
439 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
440 SEC_FILE_READ_DATA|
441 SEC_FILE_WRITE_DATA|
442 SEC_STD_DELETE,
443 FILE_ATTRIBUTE_NORMAL,
444 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
445 NTCREATEX_DISP_OPEN, 0, 0);
447 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
448 fname, smbcli_errstr(cli1->tree)));
450 torture_assert_ntstatus_ok(tctx,
451 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
452 "setting delete_on_close on file failed !");
454 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
455 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
457 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
458 talloc_asprintf(tctx, "close - 1 failed (%s)",
459 smbcli_errstr(cli1->tree)));
461 correct &= check_delete_on_close(tctx, cli1, -1, fname, true, __location__);
462 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
464 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
465 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli2->tree)));
467 /* This should fail.. */
468 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
469 torture_assert(tctx, fnum1 == -1,
470 talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !\n", fname));
472 return correct;
475 /* Test 9 ... */
476 static bool deltest9(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
478 int fnum1 = -1;
480 del_clean_area(cli1, cli2);
482 /* This should fail - we need to set DELETE_ACCESS. */
483 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
484 SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
485 FILE_ATTRIBUTE_NORMAL,
486 NTCREATEX_SHARE_ACCESS_NONE,
487 NTCREATEX_DISP_OVERWRITE_IF,
488 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
490 torture_assert(tctx, fnum1 == -1,
491 talloc_asprintf(tctx, "open of %s succeeded should have failed!",
492 fname));
494 return true;
497 /* Test 10 ... */
498 static bool deltest10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
500 int fnum1 = -1;
502 del_clean_area(cli1, cli2);
504 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
505 SEC_FILE_READ_DATA|
506 SEC_FILE_WRITE_DATA|
507 SEC_STD_DELETE,
508 FILE_ATTRIBUTE_NORMAL,
509 NTCREATEX_SHARE_ACCESS_NONE,
510 NTCREATEX_DISP_OVERWRITE_IF,
511 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
512 torture_assert(tctx, fnum1 != -1,
513 talloc_asprintf(tctx, "open of %s failed (%s)",
514 fname, smbcli_errstr(cli1->tree)));
516 /* This should delete the file. */
517 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
518 talloc_asprintf(tctx, "close failed (%s)",
519 smbcli_errstr(cli1->tree)));
521 /* This should fail.. */
522 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
523 torture_assert(tctx, fnum1 == -1,
524 talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !",
525 fname));
526 return true;
529 /* Test 11 ... */
530 static bool deltest11(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
532 int fnum1 = -1;
533 NTSTATUS status;
535 del_clean_area(cli1, cli2);
537 /* test 11 - does having read only attribute still allow delete on close. */
539 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
540 SEC_RIGHTS_FILE_ALL,
541 FILE_ATTRIBUTE_READONLY,
542 NTCREATEX_SHARE_ACCESS_NONE,
543 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
545 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
546 fname, smbcli_errstr(cli1->tree)));
548 status = smbcli_nt_delete_on_close(cli1->tree, fnum1, true);
550 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
551 talloc_asprintf(tctx, "setting delete_on_close should fail with NT_STATUS_CANNOT_DELETE. Got %s instead)", smbcli_errstr(cli1->tree)));
553 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
554 talloc_asprintf(tctx, "close failed (%s)",
555 smbcli_errstr(cli1->tree)));
557 return true;
560 /* Test 12 ... */
561 static bool deltest12(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
563 int fnum1 = -1;
564 NTSTATUS status;
566 del_clean_area(cli1, cli2);
568 /* test 12 - does having read only attribute still allow delete on
569 * close at time of open. */
571 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
572 SEC_RIGHTS_FILE_ALL,
573 FILE_ATTRIBUTE_READONLY,
574 NTCREATEX_SHARE_ACCESS_DELETE,
575 NTCREATEX_DISP_OVERWRITE_IF,
576 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
578 torture_assert(tctx, fnum1 == -1,
579 talloc_asprintf(tctx, "open of %s succeeded. Should fail with "
580 "NT_STATUS_CANNOT_DELETE.\n", fname));
582 status = smbcli_nt_error(cli1->tree);
583 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
584 talloc_asprintf(tctx, "setting delete_on_close on open should "
585 "fail with NT_STATUS_CANNOT_DELETE. Got %s "
586 "instead)",
587 smbcli_errstr(cli1->tree)));
589 return true;
592 /* Test 13 ... */
593 static bool deltest13(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
595 int fnum1 = -1;
596 int fnum2 = -1;
597 bool correct = true;
599 del_clean_area(cli1, cli2);
601 /* Test 13: Does resetting the delete on close flag affect a second
602 * fd? */
604 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
605 SEC_FILE_READ_DATA|
606 SEC_FILE_WRITE_DATA|
607 SEC_STD_DELETE,
608 FILE_ATTRIBUTE_NORMAL,
609 NTCREATEX_SHARE_ACCESS_READ|
610 NTCREATEX_SHARE_ACCESS_WRITE|
611 NTCREATEX_SHARE_ACCESS_DELETE,
612 NTCREATEX_DISP_OVERWRITE_IF,
613 0, 0);
615 torture_assert(tctx, fnum1 != -1,
616 talloc_asprintf(tctx, "open of %s failed (%s)",
617 fname, smbcli_errstr(cli1->tree)));
619 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
620 SEC_FILE_READ_DATA|
621 SEC_FILE_WRITE_DATA|
622 SEC_STD_DELETE,
623 FILE_ATTRIBUTE_NORMAL,
624 NTCREATEX_SHARE_ACCESS_READ|
625 NTCREATEX_SHARE_ACCESS_WRITE|
626 NTCREATEX_SHARE_ACCESS_DELETE,
627 NTCREATEX_DISP_OPEN, 0, 0);
629 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
630 "open of %s failed (%s)",
631 fname, smbcli_errstr(cli2->tree)));
633 torture_assert_ntstatus_ok(tctx,
634 smbcli_nt_delete_on_close(cli1->tree, fnum1,
635 true),
636 "setting delete_on_close on file failed !");
638 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
639 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
641 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli2->tree, fnum2,
642 false),
643 "setting delete_on_close on file failed !");
645 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
646 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
648 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
649 talloc_asprintf(tctx, "close - 1 failed (%s)",
650 smbcli_errstr(cli1->tree)));
652 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
653 talloc_asprintf(tctx, "close - 2 failed (%s)",
654 smbcli_errstr(cli2->tree)));
656 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
658 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed!",
659 fname));
661 smbcli_close(cli1->tree, fnum1);
663 return correct;
666 /* Test 14 ... */
667 static bool deltest14(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
669 int dnum1 = -1;
670 bool correct = true;
672 del_clean_area(cli1, cli2);
674 /* Test 14 -- directory */
676 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
677 SEC_FILE_READ_DATA|
678 SEC_FILE_WRITE_DATA|
679 SEC_STD_DELETE,
680 FILE_ATTRIBUTE_DIRECTORY,
681 NTCREATEX_SHARE_ACCESS_READ|
682 NTCREATEX_SHARE_ACCESS_WRITE|
683 NTCREATEX_SHARE_ACCESS_DELETE,
684 NTCREATEX_DISP_CREATE, 0, 0);
685 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
686 dname, smbcli_errstr(cli1->tree)));
688 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
689 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
690 "setting delete_on_close on file failed !");
691 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, true, __location__);
692 smbcli_close(cli1->tree, dnum1);
694 /* Now it should be gone... */
696 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
697 SEC_FILE_READ_DATA|
698 SEC_FILE_WRITE_DATA|
699 SEC_STD_DELETE,
700 FILE_ATTRIBUTE_DIRECTORY,
701 NTCREATEX_SHARE_ACCESS_READ|
702 NTCREATEX_SHARE_ACCESS_WRITE|
703 NTCREATEX_SHARE_ACCESS_DELETE,
704 NTCREATEX_DISP_OPEN, 0, 0);
705 torture_assert(tctx, dnum1 == -1, "setting delete_on_close on file succeeded !");
707 return correct;
710 /* Test 15 ... */
711 static bool deltest15(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
713 int fnum1 = -1;
714 bool correct = true;
715 int fnum2 = -1;
716 NTSTATUS status;
718 del_clean_area(cli1, cli2);
720 /* Test 15: delete on close under rename */
722 smbcli_setatr(cli1->tree, fname, 0, 0);
723 smbcli_unlink(cli1->tree, fname);
724 smbcli_unlink(cli1->tree, fname_new);
726 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
727 SEC_FILE_READ_DATA,
728 FILE_ATTRIBUTE_NORMAL,
729 NTCREATEX_SHARE_ACCESS_READ|
730 NTCREATEX_SHARE_ACCESS_WRITE|
731 NTCREATEX_SHARE_ACCESS_DELETE,
732 NTCREATEX_DISP_OVERWRITE_IF,
733 0, 0);
735 torture_assert(tctx, fnum1 != -1,
736 talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
738 status = smbcli_rename(cli2->tree, fname, fname_new);
740 torture_assert_ntstatus_ok(tctx, status, "renaming failed!");
742 fnum2 = smbcli_nt_create_full(cli2->tree, fname_new, 0,
743 SEC_GENERIC_ALL,
744 FILE_ATTRIBUTE_NORMAL,
745 NTCREATEX_SHARE_ACCESS_READ|
746 NTCREATEX_SHARE_ACCESS_WRITE|
747 NTCREATEX_SHARE_ACCESS_DELETE,
748 NTCREATEX_DISP_OVERWRITE_IF,
749 0, 0);
751 torture_assert(tctx, fnum2 != -1,
752 talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
753 fname_new, smbcli_errstr(cli1->tree)));
755 status = smbcli_nt_delete_on_close(cli2->tree, fnum2, true);
757 torture_assert_ntstatus_ok(tctx, status,
758 "setting delete_on_close on file failed !");
760 smbcli_close(cli2->tree, fnum2);
762 /* The file should be around under the new name, there's a second
763 * handle open */
765 correct &= check_delete_on_close(tctx, cli1, fnum1, fname_new, true, __location__);
767 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
768 SEC_GENERIC_ALL,
769 FILE_ATTRIBUTE_NORMAL,
770 NTCREATEX_SHARE_ACCESS_READ|
771 NTCREATEX_SHARE_ACCESS_WRITE|
772 NTCREATEX_SHARE_ACCESS_DELETE,
773 NTCREATEX_DISP_OVERWRITE_IF,
774 0, 0);
776 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
777 fname, smbcli_errstr(cli1->tree)));
779 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
781 smbcli_close(cli2->tree, fnum2);
782 smbcli_close(cli1->tree, fnum1);
784 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
785 SEC_FILE_READ_EA,
786 FILE_ATTRIBUTE_NORMAL,
787 NTCREATEX_SHARE_ACCESS_READ|
788 NTCREATEX_SHARE_ACCESS_WRITE|
789 NTCREATEX_SHARE_ACCESS_DELETE,
790 NTCREATEX_DISP_OPEN,
791 0, 0);
793 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
794 fname, smbcli_errstr(cli1->tree)));
796 smbcli_close(cli1->tree, fnum1);
798 fnum1 = smbcli_nt_create_full(cli1->tree, fname_new, 0,
799 SEC_FILE_READ_EA,
800 FILE_ATTRIBUTE_NORMAL,
801 NTCREATEX_SHARE_ACCESS_READ|
802 NTCREATEX_SHARE_ACCESS_WRITE|
803 NTCREATEX_SHARE_ACCESS_DELETE,
804 NTCREATEX_DISP_OPEN,
805 0, 0);
807 torture_assert(tctx, fnum1 == -1,
808 "smbcli_open succeeded, should have "
809 "failed");
811 return correct;
814 /* Test 16 ... */
815 static bool deltest16(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
817 int fnum1 = -1;
818 int fnum2 = -1;
819 bool correct = true;
821 del_clean_area(cli1, cli2);
823 /* Test 16. */
825 /* Ensure the file doesn't already exist. */
826 smbcli_close(cli1->tree, fnum1);
827 smbcli_close(cli1->tree, fnum2);
828 smbcli_setatr(cli1->tree, fname, 0, 0);
829 smbcli_unlink(cli1->tree, fname);
831 /* Firstly create with all access, but delete on close. */
832 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
833 SEC_RIGHTS_FILE_ALL,
834 FILE_ATTRIBUTE_NORMAL,
835 NTCREATEX_SHARE_ACCESS_READ|
836 NTCREATEX_SHARE_ACCESS_WRITE|
837 NTCREATEX_SHARE_ACCESS_DELETE,
838 NTCREATEX_DISP_CREATE,
839 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
841 torture_assert (tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
843 /* The delete on close bit is *not* reported as being set. */
844 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
846 /* The delete on close bit is *not* reported as being set. */
847 correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
848 correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
850 /* Now try opening again for read-only. */
851 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
852 SEC_RIGHTS_FILE_READ,
853 FILE_ATTRIBUTE_NORMAL,
854 NTCREATEX_SHARE_ACCESS_READ|
855 NTCREATEX_SHARE_ACCESS_WRITE|
856 NTCREATEX_SHARE_ACCESS_DELETE,
857 NTCREATEX_DISP_OPEN,
858 0, 0);
860 /* Should work. */
861 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
862 fname, smbcli_errstr(cli1->tree)));
864 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
865 correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
866 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
867 correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
869 smbcli_close(cli1->tree, fnum1);
871 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
872 correct &= check_delete_on_close(tctx, cli2, -1, fname, true, __location__);
874 smbcli_close(cli2->tree, fnum2);
876 /* And the file should be deleted ! */
877 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
878 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
879 fname));
881 return correct;
884 /* Test 17 ... */
885 static bool deltest17(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
887 int fnum1 = -1;
888 int fnum2 = -1;
889 bool correct = true;
891 del_clean_area(cli1, cli2);
893 /* Test 17. */
895 /* Ensure the file doesn't already exist. */
896 smbcli_close(cli1->tree, fnum1);
897 smbcli_close(cli1->tree, fnum2);
898 smbcli_setatr(cli1->tree, fname, 0, 0);
899 smbcli_unlink(cli1->tree, fname);
901 /* Firstly open and create with all access */
902 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
903 SEC_RIGHTS_FILE_ALL,
904 FILE_ATTRIBUTE_NORMAL,
905 NTCREATEX_SHARE_ACCESS_READ|
906 NTCREATEX_SHARE_ACCESS_WRITE|
907 NTCREATEX_SHARE_ACCESS_DELETE,
908 NTCREATEX_DISP_CREATE,
909 0, 0);
910 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
911 fname, smbcli_errstr(cli1->tree)));
913 /* And close - just to create the file. */
914 smbcli_close(cli1->tree, fnum1);
916 /* Next open with all access, but add delete on close. */
917 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
918 SEC_RIGHTS_FILE_ALL,
919 FILE_ATTRIBUTE_NORMAL,
920 NTCREATEX_SHARE_ACCESS_READ|
921 NTCREATEX_SHARE_ACCESS_WRITE|
922 NTCREATEX_SHARE_ACCESS_DELETE,
923 NTCREATEX_DISP_OPEN,
924 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
926 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
927 fname, smbcli_errstr(cli1->tree)));
929 /* The delete on close bit is *not* reported as being set. */
930 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
932 /* Now try opening again for read-only. */
933 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
934 SEC_RIGHTS_FILE_READ|
935 SEC_STD_DELETE,
936 FILE_ATTRIBUTE_NORMAL,
937 NTCREATEX_SHARE_ACCESS_READ|
938 NTCREATEX_SHARE_ACCESS_WRITE|
939 NTCREATEX_SHARE_ACCESS_DELETE,
940 NTCREATEX_DISP_OPEN,
941 0, 0);
943 /* Should work. */
944 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
945 fname, smbcli_errstr(cli1->tree)));
947 /* still not reported as being set on either */
948 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
949 correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
951 smbcli_close(cli1->tree, fnum1);
953 /* After the first close, the files has the delete on close bit set. */
954 correct &= check_delete_on_close(tctx, cli1, fnum2, fname, true, __location__);
956 smbcli_close(cli1->tree, fnum2);
958 /* Make sure the file has been deleted */
959 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
960 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s failed (should succeed) - %s",
961 fname, smbcli_errstr(cli1->tree)));
963 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
965 return correct;
968 /* Test 18 ... */
969 static bool deltest18(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
971 int fnum1 = -1;
972 int fnum2 = -1;
973 bool correct = true;
975 del_clean_area(cli1, cli2);
977 /* Test 18. With directories. */
979 /* Ensure the file doesn't already exist. */
980 smbcli_close(cli1->tree, fnum1);
981 smbcli_close(cli1->tree, fnum2);
983 smbcli_deltree(cli1->tree, dname);
985 /* Firstly create with all access, but delete on close. */
986 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
987 SEC_FILE_READ_DATA|
988 SEC_FILE_WRITE_DATA|
989 SEC_STD_DELETE,
990 FILE_ATTRIBUTE_DIRECTORY,
991 NTCREATEX_SHARE_ACCESS_READ|
992 NTCREATEX_SHARE_ACCESS_WRITE|
993 NTCREATEX_SHARE_ACCESS_DELETE,
994 NTCREATEX_DISP_CREATE,
995 NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
997 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
998 dname, smbcli_errstr(cli1->tree)));
1001 * The delete on close bit is *not* reported as being set.
1002 * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
1003 * close as being set. This causes the subsequent create to fail with
1004 * NT_STATUS_DELETE_PENDING.
1006 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1008 /* Now try opening again for read-only. */
1009 fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1010 SEC_RIGHTS_FILE_READ,
1011 FILE_ATTRIBUTE_DIRECTORY,
1012 NTCREATEX_SHARE_ACCESS_READ|
1013 NTCREATEX_SHARE_ACCESS_WRITE|
1014 NTCREATEX_SHARE_ACCESS_DELETE,
1015 NTCREATEX_DISP_OPEN,
1016 NTCREATEX_OPTIONS_DIRECTORY, 0);
1019 /* Should work. */
1020 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1021 dname, smbcli_errstr(cli1->tree)));
1023 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1024 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, false, __location__);
1026 smbcli_close(cli1->tree, fnum1);
1028 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
1030 smbcli_close(cli1->tree, fnum2);
1032 /* And the directory should be deleted ! */
1033 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1034 SEC_RIGHTS_FILE_READ,
1035 FILE_ATTRIBUTE_DIRECTORY,
1036 NTCREATEX_SHARE_ACCESS_READ|
1037 NTCREATEX_SHARE_ACCESS_WRITE|
1038 NTCREATEX_SHARE_ACCESS_DELETE,
1039 NTCREATEX_DISP_OPEN,
1040 NTCREATEX_OPTIONS_DIRECTORY, 0);
1041 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
1042 dname));
1044 return correct;
1047 /* Test 19 ... */
1048 static bool deltest19(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1050 int fnum1 = -1;
1051 int fnum2 = -1;
1052 bool correct = true;
1054 del_clean_area(cli1, cli2);
1056 /* Test 19. */
1058 smbcli_deltree(cli1->tree, dname);
1060 /* Firstly open and create with all access */
1061 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1062 SEC_FILE_READ_DATA|
1063 SEC_FILE_WRITE_DATA|
1064 SEC_STD_DELETE,
1065 FILE_ATTRIBUTE_DIRECTORY,
1066 NTCREATEX_SHARE_ACCESS_READ|
1067 NTCREATEX_SHARE_ACCESS_WRITE|
1068 NTCREATEX_SHARE_ACCESS_DELETE,
1069 NTCREATEX_DISP_CREATE,
1070 NTCREATEX_OPTIONS_DIRECTORY, 0);
1072 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1073 dname, smbcli_errstr(cli1->tree)));
1075 /* And close - just to create the directory. */
1076 smbcli_close(cli1->tree, fnum1);
1078 /* Next open with all access, but add delete on close. */
1079 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1080 SEC_FILE_READ_DATA|
1081 SEC_FILE_WRITE_DATA|
1082 SEC_STD_DELETE,
1083 FILE_ATTRIBUTE_DIRECTORY,
1084 NTCREATEX_SHARE_ACCESS_READ|
1085 NTCREATEX_SHARE_ACCESS_WRITE|
1086 NTCREATEX_SHARE_ACCESS_DELETE,
1087 NTCREATEX_DISP_OPEN,
1088 NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1090 torture_assert(tctx, fnum1 != -1,
1091 talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
1094 * The delete on close bit is *not* reported as being set.
1095 * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
1096 * close as being set. This causes the subsequent create to fail with
1097 * NT_STATUS_DELETE_PENDING.
1099 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1101 /* Now try opening again for read-only. */
1102 fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1103 SEC_RIGHTS_FILE_READ,
1104 FILE_ATTRIBUTE_DIRECTORY,
1105 NTCREATEX_SHARE_ACCESS_READ|
1106 NTCREATEX_SHARE_ACCESS_WRITE|
1107 NTCREATEX_SHARE_ACCESS_DELETE,
1108 NTCREATEX_DISP_OPEN,
1109 NTCREATEX_OPTIONS_DIRECTORY, 0);
1111 /* Should work. */
1112 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1113 dname, smbcli_errstr(cli1->tree)));
1115 smbcli_close(cli1->tree, fnum1);
1117 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
1119 smbcli_close(cli1->tree, fnum2);
1121 /* See if the file is deleted - for a directory this seems to be true ! */
1122 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1123 SEC_RIGHTS_FILE_READ,
1124 FILE_ATTRIBUTE_DIRECTORY,
1125 NTCREATEX_SHARE_ACCESS_READ|
1126 NTCREATEX_SHARE_ACCESS_WRITE|
1127 NTCREATEX_SHARE_ACCESS_DELETE,
1128 NTCREATEX_DISP_OPEN,
1129 NTCREATEX_OPTIONS_DIRECTORY, 0);
1131 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1133 torture_assert(tctx, fnum1 == -1,
1134 talloc_asprintf(tctx, "open of %s succeeded (should fail)", dname));
1136 return correct;
1139 /* Test 20 ... */
1140 static bool deltest20(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1142 int fnum1 = -1;
1143 int dnum1 = -1;
1144 bool correct = true;
1145 NTSTATUS status;
1147 del_clean_area(cli1, cli2);
1149 /* Test 20 -- non-empty directory hardest to get right... */
1151 if (torture_setting_bool(tctx, "samba3", false)) {
1152 return true;
1155 smbcli_deltree(cli1->tree, dname);
1157 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1158 SEC_FILE_READ_DATA|
1159 SEC_FILE_WRITE_DATA|
1160 SEC_STD_DELETE,
1161 FILE_ATTRIBUTE_DIRECTORY,
1162 NTCREATEX_SHARE_ACCESS_READ|
1163 NTCREATEX_SHARE_ACCESS_WRITE|
1164 NTCREATEX_SHARE_ACCESS_DELETE,
1165 NTCREATEX_DISP_CREATE,
1166 NTCREATEX_OPTIONS_DIRECTORY, 0);
1167 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
1168 dname, smbcli_errstr(cli1->tree)));
1170 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
1171 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1174 char *fullname;
1175 asprintf(&fullname, "\\%s%s", dname, fname);
1176 fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
1177 DENY_NONE);
1178 torture_assert(tctx, fnum1 == -1,
1179 "smbcli_open succeeded, should have "
1180 "failed with NT_STATUS_DELETE_PENDING"
1183 torture_assert_ntstatus_equal(tctx,
1184 smbcli_nt_error(cli1->tree),
1185 NT_STATUS_DELETE_PENDING,
1186 "smbcli_open failed");
1189 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, false);
1190 torture_assert_ntstatus_ok(tctx, status,
1191 "setting delete_on_close on file failed !");
1194 char *fullname;
1195 asprintf(&fullname, "\\%s%s", dname, fname);
1196 fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
1197 DENY_NONE);
1198 torture_assert(tctx, fnum1 != -1,
1199 talloc_asprintf(tctx, "smbcli_open failed: %s\n",
1200 smbcli_errstr(cli1->tree)));
1201 smbcli_close(cli1->tree, fnum1);
1204 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1206 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DIRECTORY_NOT_EMPTY,
1207 "setting delete_on_close failed");
1208 smbcli_close(cli1->tree, dnum1);
1210 return correct;
1213 /* Test 20a ... */
1214 static bool deltest20a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1216 int fnum1 = -1;
1217 int fnum2 = -1;
1218 bool correct = true;
1220 del_clean_area(cli1, cli2);
1222 /* Test 20a. */
1224 /* Ensure the file doesn't already exist. */
1225 smbcli_close(cli1->tree, fnum1);
1226 smbcli_close(cli1->tree, fnum2);
1227 smbcli_setatr(cli1->tree, fname, 0, 0);
1228 smbcli_unlink(cli1->tree, fname);
1230 /* Firstly open and create with all access */
1231 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1232 SEC_RIGHTS_FILE_ALL,
1233 FILE_ATTRIBUTE_NORMAL,
1234 NTCREATEX_SHARE_ACCESS_READ|
1235 NTCREATEX_SHARE_ACCESS_WRITE|
1236 NTCREATEX_SHARE_ACCESS_DELETE,
1237 NTCREATEX_DISP_CREATE,
1238 0, 0);
1239 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1240 fname, smbcli_errstr(cli1->tree)));
1242 /* Next open with all access, but add delete on close. */
1243 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
1244 SEC_RIGHTS_FILE_ALL,
1245 FILE_ATTRIBUTE_NORMAL,
1246 NTCREATEX_SHARE_ACCESS_READ|
1247 NTCREATEX_SHARE_ACCESS_WRITE|
1248 NTCREATEX_SHARE_ACCESS_DELETE,
1249 NTCREATEX_DISP_OPEN,
1250 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1252 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
1253 fname, smbcli_errstr(cli2->tree)));
1255 /* The delete on close bit is *not* reported as being set. */
1256 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
1257 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1259 smbcli_close(cli1->tree, fnum1);
1261 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1263 smbcli_close(cli2->tree, fnum2);
1265 /* See if the file is deleted - should be.... */
1266 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
1267 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1268 fname, smbcli_errstr(cli1->tree)));
1270 return correct;
1273 /* Test 20b ... */
1274 /* This is the delete semantics that the cifsfs client depends on when
1275 * trying to delete an open file on a Windows server. It
1276 * opens a file with initial delete on close set, renames it then closes
1277 * all open handles. The file goes away on Windows.
1280 static bool deltest20b(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1282 int fnum1 = -1;
1283 int fnum2 = -1;
1284 bool correct = true;
1286 del_clean_area(cli1, cli2);
1288 /* Test 20b. */
1290 /* Ensure the file doesn't already exist. */
1291 smbcli_close(cli1->tree, fnum1);
1292 smbcli_close(cli1->tree, fnum2);
1293 smbcli_setatr(cli1->tree, fname, 0, 0);
1294 smbcli_unlink(cli1->tree, fname);
1295 smbcli_setatr(cli1->tree, fname_new, 0, 0);
1296 smbcli_unlink(cli1->tree, fname_new);
1298 /* Firstly open and create with all access */
1299 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1300 SEC_RIGHTS_FILE_ALL,
1301 FILE_ATTRIBUTE_NORMAL,
1302 NTCREATEX_SHARE_ACCESS_READ|
1303 NTCREATEX_SHARE_ACCESS_WRITE|
1304 NTCREATEX_SHARE_ACCESS_DELETE,
1305 NTCREATEX_DISP_CREATE,
1306 0, 0);
1307 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1308 fname, smbcli_errstr(cli1->tree)));
1310 /* And close - just to create the file. */
1311 smbcli_close(cli1->tree, fnum1);
1313 /* Firstly open and create with all access */
1314 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1315 SEC_RIGHTS_FILE_ALL,
1316 FILE_ATTRIBUTE_NORMAL,
1317 NTCREATEX_SHARE_ACCESS_READ|
1318 NTCREATEX_SHARE_ACCESS_WRITE|
1319 NTCREATEX_SHARE_ACCESS_DELETE,
1320 NTCREATEX_DISP_OPEN,
1321 0, 0);
1322 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1323 fname, smbcli_errstr(cli1->tree)));
1325 /* Next open with all access, but add delete on close. */
1326 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
1327 SEC_RIGHTS_FILE_ALL,
1328 FILE_ATTRIBUTE_NORMAL,
1329 NTCREATEX_SHARE_ACCESS_READ|
1330 NTCREATEX_SHARE_ACCESS_WRITE|
1331 NTCREATEX_SHARE_ACCESS_DELETE,
1332 NTCREATEX_DISP_OPEN,
1333 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1335 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
1336 fname, smbcli_errstr(cli2->tree)));
1338 /* The delete on close bit is *not* reported as being set. */
1339 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
1340 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1342 smbcli_close(cli1->tree, fnum1);
1344 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1346 /* Rename the file by handle. */
1349 union smb_setfileinfo sfinfo;
1350 NTSTATUS status;
1352 memset(&sfinfo, '\0', sizeof(sfinfo));
1353 sfinfo.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
1354 sfinfo.generic.in.file.fnum = fnum2;
1355 sfinfo.rename_information.in.root_fid = 0;
1356 /* Don't start the filename with '\\', we get NT_STATUS_NOT_SUPPORTED if so. */
1357 sfinfo.rename_information.in.new_name = fname_new + 1;
1358 sfinfo.rename_information.in.overwrite = 1;
1360 status = smb_raw_setfileinfo(cli2->tree, &sfinfo);
1362 torture_assert_ntstatus_equal(tctx,status,NT_STATUS_OK,talloc_asprintf(tctx, "rename of %s to %s failed (%s)",
1363 fname, fname_new, smbcli_errstr(cli2->tree)));
1366 correct &= check_delete_on_close(tctx, cli2, fnum2, fname_new, false, __location__);
1368 smbcli_close(cli2->tree, fnum2);
1370 /* See if the file is deleted - should be.... */
1371 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
1372 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1373 fname, smbcli_errstr(cli1->tree)));
1374 fnum1 = smbcli_open(cli1->tree, fname_new, O_RDWR, DENY_NONE);
1375 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1376 fname_new, smbcli_errstr(cli1->tree)));
1378 return correct;
1382 /* Test 21 ... */
1383 static bool deltest21(struct torture_context *tctx)
1385 int fnum1 = -1;
1386 struct smbcli_state *cli1;
1387 struct smbcli_state *cli2;
1388 bool correct = true;
1390 if (!torture_open_connection(&cli1, tctx, 0))
1391 return false;
1393 if (!torture_open_connection(&cli2, tctx, 1))
1394 return false;
1396 del_clean_area(cli1, cli2);
1398 /* Test 21 -- Test removal of file after socket close. */
1400 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1401 SEC_RIGHTS_FILE_ALL,
1402 FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
1403 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1405 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
1406 fname, smbcli_errstr(cli1->tree)));
1408 torture_assert_ntstatus_ok(tctx,
1409 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
1410 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
1411 smbcli_errstr(cli1->tree)));
1413 /* Ensure delete on close is set. */
1414 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
1416 /* Now yank the rug from under cli1. */
1417 smbcli_transport_dead(cli1->transport, NT_STATUS_LOCAL_DISCONNECT);
1419 fnum1 = -1;
1421 if (!torture_open_connection(&cli1, tctx, 0)) {
1422 return false;
1425 /* On slow build farm machines it might happen that they are not fast
1426 * enogh to delete the file for this test */
1427 msleep(200);
1429 /* File should not be there. */
1430 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1431 SEC_RIGHTS_FILE_READ,
1432 FILE_ATTRIBUTE_NORMAL,
1433 NTCREATEX_SHARE_ACCESS_READ|
1434 NTCREATEX_SHARE_ACCESS_WRITE|
1435 NTCREATEX_SHARE_ACCESS_DELETE,
1436 NTCREATEX_DISP_OPEN,
1437 0, 0);
1439 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1441 return correct;
1444 /* Test 22 ... */
1447 * Test whether a second *directory* handle inhibits delete if the first has
1448 * del-on-close set and is closed
1450 static bool deltest22(struct torture_context *tctx)
1452 int dnum1 = -1;
1453 int dnum2 = -1;
1454 struct smbcli_state *cli1;
1455 bool correct = true;
1457 if (!torture_open_connection(&cli1, tctx, 0))
1458 return false;
1460 smbcli_deltree(cli1->tree, dname);
1462 torture_assert_ntstatus_ok(
1463 tctx, smbcli_mkdir(cli1->tree, dname),
1464 talloc_asprintf(tctx, "smbcli_mdir failed: (%s)\n",
1465 smbcli_errstr(cli1->tree)));
1467 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1468 SEC_FILE_READ_DATA|
1469 SEC_FILE_WRITE_DATA|
1470 SEC_STD_DELETE,
1471 FILE_ATTRIBUTE_DIRECTORY,
1472 NTCREATEX_SHARE_ACCESS_READ|
1473 NTCREATEX_SHARE_ACCESS_WRITE|
1474 NTCREATEX_SHARE_ACCESS_DELETE,
1475 NTCREATEX_DISP_OPEN,
1476 NTCREATEX_OPTIONS_DIRECTORY, 0);
1478 torture_assert(tctx, dnum1 != -1,
1479 talloc_asprintf(tctx, "open of %s failed: %s!",
1480 dname, smbcli_errstr(cli1->tree)));
1482 dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1483 SEC_FILE_READ_DATA|
1484 SEC_FILE_WRITE_DATA,
1485 FILE_ATTRIBUTE_DIRECTORY,
1486 NTCREATEX_SHARE_ACCESS_READ|
1487 NTCREATEX_SHARE_ACCESS_WRITE|
1488 NTCREATEX_SHARE_ACCESS_DELETE,
1489 NTCREATEX_DISP_OPEN,
1490 NTCREATEX_OPTIONS_DIRECTORY, 0);
1492 torture_assert(tctx, dnum2 != -1,
1493 talloc_asprintf(tctx, "open of %s failed: %s!",
1494 dname, smbcli_errstr(cli1->tree)));
1496 torture_assert_ntstatus_ok(
1497 tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
1498 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
1499 smbcli_errstr(cli1->tree)));
1501 smbcli_close(cli1->tree, dnum1);
1503 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1504 SEC_FILE_READ_DATA|
1505 SEC_FILE_WRITE_DATA|
1506 SEC_STD_DELETE,
1507 FILE_ATTRIBUTE_DIRECTORY,
1508 NTCREATEX_SHARE_ACCESS_READ|
1509 NTCREATEX_SHARE_ACCESS_WRITE|
1510 NTCREATEX_SHARE_ACCESS_DELETE,
1511 NTCREATEX_DISP_OPEN,
1512 NTCREATEX_OPTIONS_DIRECTORY, 0);
1514 torture_assert(tctx, dnum1 == -1,
1515 talloc_asprintf(tctx, "open of %s succeeded!\n",
1516 dname));
1518 CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
1520 return correct;
1524 Test delete on close semantics.
1526 struct torture_suite *torture_test_delete(void)
1528 struct torture_suite *suite = torture_suite_create(
1529 talloc_autofree_context(),
1530 "DELETE");
1532 torture_suite_add_2smb_test(suite, "deltest1", deltest1);
1533 torture_suite_add_2smb_test(suite, "deltest2", deltest2);
1534 torture_suite_add_2smb_test(suite, "deltest3", deltest3);
1535 torture_suite_add_2smb_test(suite, "deltest4", deltest4);
1536 torture_suite_add_2smb_test(suite, "deltest5", deltest5);
1537 torture_suite_add_2smb_test(suite, "deltest6", deltest6);
1538 torture_suite_add_2smb_test(suite, "deltest7", deltest7);
1539 torture_suite_add_2smb_test(suite, "deltest8", deltest8);
1540 torture_suite_add_2smb_test(suite, "deltest9", deltest9);
1541 torture_suite_add_2smb_test(suite, "deltest10", deltest10);
1542 torture_suite_add_2smb_test(suite, "deltest11", deltest11);
1543 torture_suite_add_2smb_test(suite, "deltest12", deltest12);
1544 torture_suite_add_2smb_test(suite, "deltest13", deltest13);
1545 torture_suite_add_2smb_test(suite, "deltest14", deltest14);
1546 torture_suite_add_2smb_test(suite, "deltest15", deltest15);
1547 torture_suite_add_2smb_test(suite, "deltest16", deltest16);
1548 torture_suite_add_2smb_test(suite, "deltest17", deltest17);
1549 torture_suite_add_2smb_test(suite, "deltest18", deltest18);
1550 torture_suite_add_2smb_test(suite, "deltest19", deltest19);
1551 torture_suite_add_2smb_test(suite, "deltest20", deltest20);
1552 torture_suite_add_2smb_test(suite, "deltest20a", deltest20a);
1553 torture_suite_add_2smb_test(suite, "deltest20b", deltest20b);
1554 torture_suite_add_simple_test(suite, "deltest21", deltest21);
1555 torture_suite_add_simple_test(suite, "deltest22", deltest22);
1557 return suite;