s4-smbtorture: Make test names lowercase and dot-separated.
[Samba.git] / source4 / torture / basic / delete.c
blob888c5a6b468efd7b114155ca69e1c6b62860311d
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/util.h"
25 #include "system/filesys.h"
26 #include "libcli/raw/raw_proto.h"
28 #include "torture/raw/proto.h"
30 static bool check_delete_on_close(struct torture_context *tctx,
31 struct smbcli_state *cli, int fnum,
32 const char *fname, bool expect_it,
33 const char *where)
35 union smb_search_data data;
36 NTSTATUS status;
38 time_t c_time, a_time, m_time;
39 size_t size;
40 uint16_t mode;
42 status = torture_single_search(cli, tctx,
43 fname,
44 RAW_SEARCH_TRANS2,
45 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
46 FILE_ATTRIBUTE_DIRECTORY,
47 &data);
48 torture_assert_ntstatus_ok(tctx, status,
49 talloc_asprintf(tctx, "single_search failed (%s)", where));
51 if (fnum != -1) {
52 union smb_fileinfo io;
53 int nlink = expect_it ? 0 : 1;
55 io.all_info.level = RAW_FILEINFO_ALL_INFO;
56 io.all_info.in.file.fnum = fnum;
58 status = smb_raw_fileinfo(cli->tree, tctx, &io);
59 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx,
60 "qfileinfo failed (%s)", where));
62 torture_assert(tctx, expect_it == io.all_info.out.delete_pending,
63 talloc_asprintf(tctx,
64 "%s - Expected del_on_close flag %d, qfileinfo/all_info gave %d",
65 where, expect_it, io.all_info.out.delete_pending));
67 torture_assert(tctx, nlink == io.all_info.out.nlink,
68 talloc_asprintf(tctx,
69 "%s - Expected nlink %d, qfileinfo/all_info gave %d",
70 where, nlink, io.all_info.out.nlink));
72 io.standard_info.level = RAW_FILEINFO_STANDARD_INFO;
73 io.standard_info.in.file.fnum = fnum;
75 status = smb_raw_fileinfo(cli->tree, tctx, &io);
76 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
78 torture_assert(tctx, expect_it == io.standard_info.out.delete_pending,
79 talloc_asprintf(tctx, "%s - Expected del_on_close flag %d, qfileinfo/standard_info gave %d\n",
80 where, expect_it, io.standard_info.out.delete_pending));
82 torture_assert(tctx, nlink == io.standard_info.out.nlink,
83 talloc_asprintf(tctx, "%s - Expected nlink %d, qfileinfo/standard_info gave %d",
84 where, nlink, io.all_info.out.nlink));
87 status = smbcli_qpathinfo(cli->tree, fname,
88 &c_time, &a_time, &m_time,
89 &size, &mode);
91 if (expect_it) {
92 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
93 "qpathinfo did not give correct error code");
94 } else {
95 torture_assert_ntstatus_ok(tctx, status,
96 talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
99 return true;
102 #define CHECK_STATUS(_cli, _expected) \
103 torture_assert_ntstatus_equal(tctx, _cli->tree->session->transport->error.e.nt_status, _expected, \
104 "Incorrect status")
106 static const char *fname = "\\delete.file";
107 static const char *fname_new = "\\delete.new";
108 static const char *dname = "\\delete.dir";
110 static void del_clean_area(struct smbcli_state *cli1, struct smbcli_state *cli2)
112 smb_raw_exit(cli1->session);
113 smb_raw_exit(cli2->session);
115 smbcli_deltree(cli1->tree, dname);
116 smbcli_setatr(cli1->tree, fname, 0, 0);
117 smbcli_unlink(cli1->tree, fname);
118 smbcli_setatr(cli1->tree, fname_new, 0, 0);
119 smbcli_unlink(cli1->tree, fname_new);
122 /* Test 1 - this should delete the file on close. */
124 static bool deltest1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
126 int fnum1 = -1;
128 del_clean_area(cli1, cli2);
130 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
131 SEC_RIGHTS_FILE_ALL,
132 FILE_ATTRIBUTE_NORMAL,
133 NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OVERWRITE_IF,
134 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
136 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
137 fname, smbcli_errstr(cli1->tree)));
139 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
140 talloc_asprintf(tctx, "close failed (%s)", smbcli_errstr(cli1->tree)));
142 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
143 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
144 fname));
146 return true;
149 /* Test 2 - this should delete the file on close. */
150 static bool deltest2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
152 int fnum1 = -1;
154 del_clean_area(cli1, cli2);
156 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
157 SEC_RIGHTS_FILE_ALL,
158 FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
159 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
161 torture_assert(tctx, fnum1 != -1,
162 talloc_asprintf(tctx, "open of %s failed (%s)",
163 fname, smbcli_errstr(cli1->tree)));
165 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
166 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
167 smbcli_errstr(cli1->tree)));
169 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
170 talloc_asprintf(tctx, "close failed (%s)",
171 smbcli_errstr(cli1->tree)));
173 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
174 if (fnum1 != -1) {
175 printf("(%s) open of %s succeeded should have been deleted on close !\n",
176 __location__, fname);
177 if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
178 printf("(%s) close failed (%s)\n",
179 __location__, smbcli_errstr(cli1->tree));
180 return false;
182 smbcli_unlink(cli1->tree, fname);
184 return true;
187 /* Test 3 - ... */
188 static bool deltest3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
190 int fnum1 = -1;
191 int fnum2 = -1;
193 del_clean_area(cli1, cli2);
195 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
196 SEC_RIGHTS_FILE_ALL,
197 FILE_ATTRIBUTE_NORMAL,
198 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
199 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
201 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
202 fname, smbcli_errstr(cli1->tree)));
204 /* This should fail with a sharing violation - open for delete is only compatible
205 with SHARE_DELETE. */
207 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
208 SEC_RIGHTS_FILE_READ,
209 FILE_ATTRIBUTE_NORMAL,
210 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
211 NTCREATEX_DISP_OPEN, 0, 0);
213 torture_assert(tctx, fnum2 == -1,
214 talloc_asprintf(tctx, "open - 2 of %s succeeded - should have failed.",
215 fname));
217 /* This should succeed. */
219 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
220 SEC_RIGHTS_FILE_READ,
221 FILE_ATTRIBUTE_NORMAL,
222 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
223 NTCREATEX_DISP_OPEN, 0, 0);
225 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
226 fname, smbcli_errstr(cli1->tree)));
228 torture_assert_ntstatus_ok(tctx,
229 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
230 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
231 smbcli_errstr(cli1->tree)));
233 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
234 talloc_asprintf(tctx, "close 1 failed (%s)",
235 smbcli_errstr(cli1->tree)));
237 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
238 talloc_asprintf(tctx, "close 2 failed (%s)",
239 smbcli_errstr(cli1->tree)));
241 /* This should fail - file should no longer be there. */
243 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
244 if (fnum1 != -1) {
245 printf("(%s) open of %s succeeded should have been deleted on close !\n",
246 __location__, fname);
247 if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
248 printf("(%s) close failed (%s)\n",
249 __location__, smbcli_errstr(cli1->tree));
251 smbcli_unlink(cli1->tree, fname);
252 return false;
254 return true;
257 /* Test 4 ... */
258 static bool deltest4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
260 int fnum1 = -1;
261 int fnum2 = -1;
262 bool correct = true;
264 del_clean_area(cli1, cli2);
266 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
267 SEC_FILE_READ_DATA |
268 SEC_FILE_WRITE_DATA |
269 SEC_STD_DELETE,
270 FILE_ATTRIBUTE_NORMAL,
271 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
272 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
274 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
275 fname, smbcli_errstr(cli1->tree)));
277 /* This should succeed. */
278 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
279 SEC_RIGHTS_FILE_READ,
280 FILE_ATTRIBUTE_NORMAL,
281 NTCREATEX_SHARE_ACCESS_READ |
282 NTCREATEX_SHARE_ACCESS_WRITE |
283 NTCREATEX_SHARE_ACCESS_DELETE,
284 NTCREATEX_DISP_OPEN, 0, 0);
285 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
286 fname, smbcli_errstr(cli1->tree)));
288 torture_assert_ntstatus_ok(tctx,
289 smbcli_close(cli1->tree, fnum2),
290 talloc_asprintf(tctx, "close - 1 failed (%s)",
291 smbcli_errstr(cli1->tree)));
293 torture_assert_ntstatus_ok(tctx,
294 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
295 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
296 smbcli_errstr(cli1->tree)));
298 /* This should fail - no more opens once delete on close set. */
299 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
300 SEC_RIGHTS_FILE_READ,
301 FILE_ATTRIBUTE_NORMAL,
302 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
303 NTCREATEX_DISP_OPEN, 0, 0);
304 torture_assert(tctx, fnum2 == -1,
305 talloc_asprintf(tctx, "open - 3 of %s succeeded ! Should have failed.",
306 fname ));
308 CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
310 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
311 talloc_asprintf(tctx, "close - 2 failed (%s)",
312 smbcli_errstr(cli1->tree)));
314 return correct;
317 /* Test 5 ... */
318 static bool deltest5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
320 int fnum1 = -1;
322 del_clean_area(cli1, cli2);
324 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
325 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
326 fname, smbcli_errstr(cli1->tree)));
328 /* This should fail - only allowed on NT opens with DELETE access. */
330 torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
331 "setting delete_on_close on OpenX file succeeded - should fail !");
333 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
334 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
336 return true;
339 /* Test 6 ... */
340 static bool deltest6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
342 int fnum1 = -1;
344 del_clean_area(cli1, cli2);
346 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
347 SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
348 FILE_ATTRIBUTE_NORMAL,
349 NTCREATEX_SHARE_ACCESS_READ |
350 NTCREATEX_SHARE_ACCESS_WRITE |
351 NTCREATEX_SHARE_ACCESS_DELETE,
352 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
354 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
355 fname, smbcli_errstr(cli1->tree)));
357 /* This should fail - only allowed on NT opens with DELETE access. */
359 torture_assert(tctx,
360 !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
361 "setting delete_on_close on file with no delete access succeeded - should fail !");
363 torture_assert_ntstatus_ok(tctx,
364 smbcli_close(cli1->tree, fnum1),
365 talloc_asprintf(tctx, "close - 2 failed (%s)",
366 smbcli_errstr(cli1->tree)));
368 return true;
371 /* Test 7 ... */
372 static bool deltest7(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
374 int fnum1 = -1;
375 bool correct = true;
377 del_clean_area(cli1, cli2);
379 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
380 SEC_FILE_READ_DATA |
381 SEC_FILE_WRITE_DATA |
382 SEC_STD_DELETE,
383 FILE_ATTRIBUTE_NORMAL, 0,
384 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
386 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
387 fname, smbcli_errstr(cli1->tree)));
389 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
390 "setting delete_on_close on file failed !");
392 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
394 torture_assert_ntstatus_ok(tctx,
395 smbcli_nt_delete_on_close(cli1->tree, fnum1, false),
396 "unsetting delete_on_close on file failed !");
398 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
400 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
401 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
403 /* This next open should succeed - we reset the flag. */
405 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
406 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
407 fname, smbcli_errstr(cli1->tree)));
409 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
410 talloc_asprintf(tctx, "close - 2 failed (%s)",
411 smbcli_errstr(cli1->tree)));
413 return correct;
416 /* Test 8 ... */
417 static bool deltest8(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
419 int fnum1 = -1;
420 int fnum2 = -1;
421 bool correct = true;
423 del_clean_area(cli1, cli2);
425 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
426 SEC_FILE_READ_DATA|
427 SEC_FILE_WRITE_DATA|
428 SEC_STD_DELETE,
429 FILE_ATTRIBUTE_NORMAL,
430 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
431 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
433 torture_assert(tctx, fnum1 != -1,
434 talloc_asprintf(tctx, "open of %s failed (%s)",
435 fname, smbcli_errstr(cli1->tree)));
437 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
438 SEC_FILE_READ_DATA|
439 SEC_FILE_WRITE_DATA|
440 SEC_STD_DELETE,
441 FILE_ATTRIBUTE_NORMAL,
442 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
443 NTCREATEX_DISP_OPEN, 0, 0);
445 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
446 fname, smbcli_errstr(cli1->tree)));
448 torture_assert_ntstatus_ok(tctx,
449 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
450 "setting delete_on_close on file failed !");
452 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
453 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
455 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
456 talloc_asprintf(tctx, "close - 1 failed (%s)",
457 smbcli_errstr(cli1->tree)));
459 correct &= check_delete_on_close(tctx, cli1, -1, fname, true, __location__);
460 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
462 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
463 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli2->tree)));
465 /* This should fail.. */
466 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
467 torture_assert(tctx, fnum1 == -1,
468 talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !\n", fname));
470 return correct;
473 /* Test 9 ... */
474 static bool deltest9(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
476 int fnum1 = -1;
478 del_clean_area(cli1, cli2);
480 /* This should fail - we need to set DELETE_ACCESS. */
481 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
482 SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
483 FILE_ATTRIBUTE_NORMAL,
484 NTCREATEX_SHARE_ACCESS_NONE,
485 NTCREATEX_DISP_OVERWRITE_IF,
486 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
488 torture_assert(tctx, fnum1 == -1,
489 talloc_asprintf(tctx, "open of %s succeeded should have failed!",
490 fname));
492 return true;
495 /* Test 10 ... */
496 static bool deltest10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
498 int fnum1 = -1;
500 del_clean_area(cli1, cli2);
502 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
503 SEC_FILE_READ_DATA|
504 SEC_FILE_WRITE_DATA|
505 SEC_STD_DELETE,
506 FILE_ATTRIBUTE_NORMAL,
507 NTCREATEX_SHARE_ACCESS_NONE,
508 NTCREATEX_DISP_OVERWRITE_IF,
509 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
510 torture_assert(tctx, fnum1 != -1,
511 talloc_asprintf(tctx, "open of %s failed (%s)",
512 fname, smbcli_errstr(cli1->tree)));
514 /* This should delete the file. */
515 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
516 talloc_asprintf(tctx, "close failed (%s)",
517 smbcli_errstr(cli1->tree)));
519 /* This should fail.. */
520 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
521 torture_assert(tctx, fnum1 == -1,
522 talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !",
523 fname));
524 return true;
527 /* Test 11 ... */
528 static bool deltest11(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
530 int fnum1 = -1;
531 NTSTATUS status;
533 del_clean_area(cli1, cli2);
535 /* test 11 - does having read only attribute still allow delete on close. */
537 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
538 SEC_RIGHTS_FILE_ALL,
539 FILE_ATTRIBUTE_READONLY,
540 NTCREATEX_SHARE_ACCESS_NONE,
541 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
543 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
544 fname, smbcli_errstr(cli1->tree)));
546 status = smbcli_nt_delete_on_close(cli1->tree, fnum1, true);
548 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
549 talloc_asprintf(tctx, "setting delete_on_close should fail with NT_STATUS_CANNOT_DELETE. Got %s instead)", smbcli_errstr(cli1->tree)));
551 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
552 talloc_asprintf(tctx, "close failed (%s)",
553 smbcli_errstr(cli1->tree)));
555 return true;
558 /* Test 12 ... */
559 static bool deltest12(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
561 int fnum1 = -1;
562 NTSTATUS status;
564 del_clean_area(cli1, cli2);
566 /* test 12 - does having read only attribute still allow delete on
567 * close at time of open. */
569 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
570 SEC_RIGHTS_FILE_ALL,
571 FILE_ATTRIBUTE_READONLY,
572 NTCREATEX_SHARE_ACCESS_DELETE,
573 NTCREATEX_DISP_OVERWRITE_IF,
574 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
576 torture_assert(tctx, fnum1 == -1,
577 talloc_asprintf(tctx, "open of %s succeeded. Should fail with "
578 "NT_STATUS_CANNOT_DELETE.\n", fname));
580 status = smbcli_nt_error(cli1->tree);
581 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
582 talloc_asprintf(tctx, "setting delete_on_close on open should "
583 "fail with NT_STATUS_CANNOT_DELETE. Got %s "
584 "instead)",
585 smbcli_errstr(cli1->tree)));
587 return true;
590 /* Test 13 ... */
591 static bool deltest13(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
593 int fnum1 = -1;
594 int fnum2 = -1;
595 bool correct = true;
597 del_clean_area(cli1, cli2);
599 /* Test 13: Does resetting the delete on close flag affect a second
600 * fd? */
602 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
603 SEC_FILE_READ_DATA|
604 SEC_FILE_WRITE_DATA|
605 SEC_STD_DELETE,
606 FILE_ATTRIBUTE_NORMAL,
607 NTCREATEX_SHARE_ACCESS_READ|
608 NTCREATEX_SHARE_ACCESS_WRITE|
609 NTCREATEX_SHARE_ACCESS_DELETE,
610 NTCREATEX_DISP_OVERWRITE_IF,
611 0, 0);
613 torture_assert(tctx, fnum1 != -1,
614 talloc_asprintf(tctx, "open of %s failed (%s)",
615 fname, smbcli_errstr(cli1->tree)));
617 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
618 SEC_FILE_READ_DATA|
619 SEC_FILE_WRITE_DATA|
620 SEC_STD_DELETE,
621 FILE_ATTRIBUTE_NORMAL,
622 NTCREATEX_SHARE_ACCESS_READ|
623 NTCREATEX_SHARE_ACCESS_WRITE|
624 NTCREATEX_SHARE_ACCESS_DELETE,
625 NTCREATEX_DISP_OPEN, 0, 0);
627 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
628 "open of %s failed (%s)",
629 fname, smbcli_errstr(cli2->tree)));
631 torture_assert_ntstatus_ok(tctx,
632 smbcli_nt_delete_on_close(cli1->tree, fnum1,
633 true),
634 "setting delete_on_close on file failed !");
636 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
637 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
639 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli2->tree, fnum2,
640 false),
641 "setting delete_on_close on file failed !");
643 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
644 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
646 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
647 talloc_asprintf(tctx, "close - 1 failed (%s)",
648 smbcli_errstr(cli1->tree)));
650 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
651 talloc_asprintf(tctx, "close - 2 failed (%s)",
652 smbcli_errstr(cli2->tree)));
654 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
656 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed!",
657 fname));
659 smbcli_close(cli1->tree, fnum1);
661 return correct;
664 /* Test 14 ... */
665 static bool deltest14(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
667 int dnum1 = -1;
668 bool correct = true;
670 del_clean_area(cli1, cli2);
672 /* Test 14 -- directory */
674 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
675 SEC_FILE_READ_DATA|
676 SEC_FILE_WRITE_DATA|
677 SEC_STD_DELETE,
678 FILE_ATTRIBUTE_DIRECTORY,
679 NTCREATEX_SHARE_ACCESS_READ|
680 NTCREATEX_SHARE_ACCESS_WRITE|
681 NTCREATEX_SHARE_ACCESS_DELETE,
682 NTCREATEX_DISP_CREATE, 0, 0);
683 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
684 dname, smbcli_errstr(cli1->tree)));
686 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
687 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
688 "setting delete_on_close on file failed !");
689 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, true, __location__);
690 smbcli_close(cli1->tree, dnum1);
692 /* Now it should be gone... */
694 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
695 SEC_FILE_READ_DATA|
696 SEC_FILE_WRITE_DATA|
697 SEC_STD_DELETE,
698 FILE_ATTRIBUTE_DIRECTORY,
699 NTCREATEX_SHARE_ACCESS_READ|
700 NTCREATEX_SHARE_ACCESS_WRITE|
701 NTCREATEX_SHARE_ACCESS_DELETE,
702 NTCREATEX_DISP_OPEN, 0, 0);
703 torture_assert(tctx, dnum1 == -1, "setting delete_on_close on file succeeded !");
705 return correct;
708 /* Test 15 ... */
709 static bool deltest15(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
711 int fnum1 = -1;
712 bool correct = true;
713 int fnum2 = -1;
714 NTSTATUS status;
716 del_clean_area(cli1, cli2);
718 /* Test 15: delete on close under rename */
720 smbcli_setatr(cli1->tree, fname, 0, 0);
721 smbcli_unlink(cli1->tree, fname);
722 smbcli_unlink(cli1->tree, fname_new);
724 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
725 SEC_FILE_READ_DATA,
726 FILE_ATTRIBUTE_NORMAL,
727 NTCREATEX_SHARE_ACCESS_READ|
728 NTCREATEX_SHARE_ACCESS_WRITE|
729 NTCREATEX_SHARE_ACCESS_DELETE,
730 NTCREATEX_DISP_OVERWRITE_IF,
731 0, 0);
733 torture_assert(tctx, fnum1 != -1,
734 talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
736 status = smbcli_rename(cli2->tree, fname, fname_new);
738 torture_assert_ntstatus_ok(tctx, status, "renaming failed!");
740 fnum2 = smbcli_nt_create_full(cli2->tree, fname_new, 0,
741 SEC_GENERIC_ALL,
742 FILE_ATTRIBUTE_NORMAL,
743 NTCREATEX_SHARE_ACCESS_READ|
744 NTCREATEX_SHARE_ACCESS_WRITE|
745 NTCREATEX_SHARE_ACCESS_DELETE,
746 NTCREATEX_DISP_OVERWRITE_IF,
747 0, 0);
749 torture_assert(tctx, fnum2 != -1,
750 talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
751 fname_new, smbcli_errstr(cli1->tree)));
753 status = smbcli_nt_delete_on_close(cli2->tree, fnum2, true);
755 torture_assert_ntstatus_ok(tctx, status,
756 "setting delete_on_close on file failed !");
758 smbcli_close(cli2->tree, fnum2);
760 /* The file should be around under the new name, there's a second
761 * handle open */
763 correct &= check_delete_on_close(tctx, cli1, fnum1, fname_new, true, __location__);
765 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
766 SEC_GENERIC_ALL,
767 FILE_ATTRIBUTE_NORMAL,
768 NTCREATEX_SHARE_ACCESS_READ|
769 NTCREATEX_SHARE_ACCESS_WRITE|
770 NTCREATEX_SHARE_ACCESS_DELETE,
771 NTCREATEX_DISP_OVERWRITE_IF,
772 0, 0);
774 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
775 fname, smbcli_errstr(cli1->tree)));
777 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
779 smbcli_close(cli2->tree, fnum2);
780 smbcli_close(cli1->tree, fnum1);
782 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
783 SEC_FILE_READ_EA,
784 FILE_ATTRIBUTE_NORMAL,
785 NTCREATEX_SHARE_ACCESS_READ|
786 NTCREATEX_SHARE_ACCESS_WRITE|
787 NTCREATEX_SHARE_ACCESS_DELETE,
788 NTCREATEX_DISP_OPEN,
789 0, 0);
791 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
792 fname, smbcli_errstr(cli1->tree)));
794 smbcli_close(cli1->tree, fnum1);
796 fnum1 = smbcli_nt_create_full(cli1->tree, fname_new, 0,
797 SEC_FILE_READ_EA,
798 FILE_ATTRIBUTE_NORMAL,
799 NTCREATEX_SHARE_ACCESS_READ|
800 NTCREATEX_SHARE_ACCESS_WRITE|
801 NTCREATEX_SHARE_ACCESS_DELETE,
802 NTCREATEX_DISP_OPEN,
803 0, 0);
805 torture_assert(tctx, fnum1 == -1,
806 "smbcli_open succeeded, should have "
807 "failed");
809 return correct;
812 /* Test 16 ... */
813 static bool deltest16(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
815 int fnum1 = -1;
816 int fnum2 = -1;
817 bool correct = true;
819 del_clean_area(cli1, cli2);
821 /* Test 16. */
823 /* Ensure the file doesn't already exist. */
824 smbcli_close(cli1->tree, fnum1);
825 smbcli_close(cli1->tree, fnum2);
826 smbcli_setatr(cli1->tree, fname, 0, 0);
827 smbcli_unlink(cli1->tree, fname);
829 /* Firstly create with all access, but delete on close. */
830 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
831 SEC_RIGHTS_FILE_ALL,
832 FILE_ATTRIBUTE_NORMAL,
833 NTCREATEX_SHARE_ACCESS_READ|
834 NTCREATEX_SHARE_ACCESS_WRITE|
835 NTCREATEX_SHARE_ACCESS_DELETE,
836 NTCREATEX_DISP_CREATE,
837 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
839 torture_assert (tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
841 /* The delete on close bit is *not* reported as being set. */
842 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
844 /* The delete on close bit is *not* reported as being set. */
845 correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
846 correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
848 /* Now try opening again for read-only. */
849 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
850 SEC_RIGHTS_FILE_READ,
851 FILE_ATTRIBUTE_NORMAL,
852 NTCREATEX_SHARE_ACCESS_READ|
853 NTCREATEX_SHARE_ACCESS_WRITE|
854 NTCREATEX_SHARE_ACCESS_DELETE,
855 NTCREATEX_DISP_OPEN,
856 0, 0);
858 /* Should work. */
859 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
860 fname, smbcli_errstr(cli1->tree)));
862 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
863 correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
864 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
865 correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
867 smbcli_close(cli1->tree, fnum1);
869 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
870 correct &= check_delete_on_close(tctx, cli2, -1, fname, true, __location__);
872 smbcli_close(cli2->tree, fnum2);
874 /* And the file should be deleted ! */
875 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
876 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
877 fname));
879 return correct;
882 /* Test 17 ... */
883 static bool deltest17(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
885 int fnum1 = -1;
886 int fnum2 = -1;
887 bool correct = true;
889 del_clean_area(cli1, cli2);
891 /* Test 17. */
893 /* Ensure the file doesn't already exist. */
894 smbcli_close(cli1->tree, fnum1);
895 smbcli_close(cli1->tree, fnum2);
896 smbcli_setatr(cli1->tree, fname, 0, 0);
897 smbcli_unlink(cli1->tree, fname);
899 /* Firstly open and create with all access */
900 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
901 SEC_RIGHTS_FILE_ALL,
902 FILE_ATTRIBUTE_NORMAL,
903 NTCREATEX_SHARE_ACCESS_READ|
904 NTCREATEX_SHARE_ACCESS_WRITE|
905 NTCREATEX_SHARE_ACCESS_DELETE,
906 NTCREATEX_DISP_CREATE,
907 0, 0);
908 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
909 fname, smbcli_errstr(cli1->tree)));
911 /* And close - just to create the file. */
912 smbcli_close(cli1->tree, fnum1);
914 /* Next open with all access, but add delete on close. */
915 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
916 SEC_RIGHTS_FILE_ALL,
917 FILE_ATTRIBUTE_NORMAL,
918 NTCREATEX_SHARE_ACCESS_READ|
919 NTCREATEX_SHARE_ACCESS_WRITE|
920 NTCREATEX_SHARE_ACCESS_DELETE,
921 NTCREATEX_DISP_OPEN,
922 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
924 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
925 fname, smbcli_errstr(cli1->tree)));
927 /* The delete on close bit is *not* reported as being set. */
928 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
930 /* Now try opening again for read-only. */
931 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
932 SEC_RIGHTS_FILE_READ|
933 SEC_STD_DELETE,
934 FILE_ATTRIBUTE_NORMAL,
935 NTCREATEX_SHARE_ACCESS_READ|
936 NTCREATEX_SHARE_ACCESS_WRITE|
937 NTCREATEX_SHARE_ACCESS_DELETE,
938 NTCREATEX_DISP_OPEN,
939 0, 0);
941 /* Should work. */
942 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
943 fname, smbcli_errstr(cli1->tree)));
945 /* still not reported as being set on either */
946 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
947 correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
949 smbcli_close(cli1->tree, fnum1);
951 /* After the first close, the files has the delete on close bit set. */
952 correct &= check_delete_on_close(tctx, cli1, fnum2, fname, true, __location__);
954 smbcli_close(cli1->tree, fnum2);
956 /* Make sure the file has been deleted */
957 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
958 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s failed (should succeed) - %s",
959 fname, smbcli_errstr(cli1->tree)));
961 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
963 return correct;
966 /* Test 18 ... */
967 static bool deltest18(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
969 int fnum1 = -1;
970 int fnum2 = -1;
971 bool correct = true;
973 del_clean_area(cli1, cli2);
975 /* Test 18. With directories. */
977 /* Ensure the file doesn't already exist. */
978 smbcli_close(cli1->tree, fnum1);
979 smbcli_close(cli1->tree, fnum2);
981 smbcli_deltree(cli1->tree, dname);
983 /* Firstly create with all access, but delete on close. */
984 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
985 SEC_FILE_READ_DATA|
986 SEC_FILE_WRITE_DATA|
987 SEC_STD_DELETE,
988 FILE_ATTRIBUTE_DIRECTORY,
989 NTCREATEX_SHARE_ACCESS_READ|
990 NTCREATEX_SHARE_ACCESS_WRITE|
991 NTCREATEX_SHARE_ACCESS_DELETE,
992 NTCREATEX_DISP_CREATE,
993 NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
995 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
996 dname, smbcli_errstr(cli1->tree)));
999 * The delete on close bit is *not* reported as being set.
1000 * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
1001 * close as being set. This causes the subsequent create to fail with
1002 * NT_STATUS_DELETE_PENDING.
1004 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1006 /* Now try opening again for read-only. */
1007 fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1008 SEC_RIGHTS_FILE_READ,
1009 FILE_ATTRIBUTE_DIRECTORY,
1010 NTCREATEX_SHARE_ACCESS_READ|
1011 NTCREATEX_SHARE_ACCESS_WRITE|
1012 NTCREATEX_SHARE_ACCESS_DELETE,
1013 NTCREATEX_DISP_OPEN,
1014 NTCREATEX_OPTIONS_DIRECTORY, 0);
1017 /* Should work. */
1018 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1019 dname, smbcli_errstr(cli1->tree)));
1021 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1022 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, false, __location__);
1024 smbcli_close(cli1->tree, fnum1);
1026 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
1028 smbcli_close(cli1->tree, fnum2);
1030 /* And the directory should be deleted ! */
1031 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1032 SEC_RIGHTS_FILE_READ,
1033 FILE_ATTRIBUTE_DIRECTORY,
1034 NTCREATEX_SHARE_ACCESS_READ|
1035 NTCREATEX_SHARE_ACCESS_WRITE|
1036 NTCREATEX_SHARE_ACCESS_DELETE,
1037 NTCREATEX_DISP_OPEN,
1038 NTCREATEX_OPTIONS_DIRECTORY, 0);
1039 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
1040 dname));
1042 return correct;
1045 /* Test 19 ... */
1046 static bool deltest19(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1048 int fnum1 = -1;
1049 int fnum2 = -1;
1050 bool correct = true;
1052 del_clean_area(cli1, cli2);
1054 /* Test 19. */
1056 smbcli_deltree(cli1->tree, dname);
1058 /* Firstly open and create with all access */
1059 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1060 SEC_FILE_READ_DATA|
1061 SEC_FILE_WRITE_DATA|
1062 SEC_STD_DELETE,
1063 FILE_ATTRIBUTE_DIRECTORY,
1064 NTCREATEX_SHARE_ACCESS_READ|
1065 NTCREATEX_SHARE_ACCESS_WRITE|
1066 NTCREATEX_SHARE_ACCESS_DELETE,
1067 NTCREATEX_DISP_CREATE,
1068 NTCREATEX_OPTIONS_DIRECTORY, 0);
1070 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1071 dname, smbcli_errstr(cli1->tree)));
1073 /* And close - just to create the directory. */
1074 smbcli_close(cli1->tree, fnum1);
1076 /* Next open with all access, but add delete on close. */
1077 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1078 SEC_FILE_READ_DATA|
1079 SEC_FILE_WRITE_DATA|
1080 SEC_STD_DELETE,
1081 FILE_ATTRIBUTE_DIRECTORY,
1082 NTCREATEX_SHARE_ACCESS_READ|
1083 NTCREATEX_SHARE_ACCESS_WRITE|
1084 NTCREATEX_SHARE_ACCESS_DELETE,
1085 NTCREATEX_DISP_OPEN,
1086 NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1088 torture_assert(tctx, fnum1 != -1,
1089 talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
1092 * The delete on close bit is *not* reported as being set.
1093 * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
1094 * close as being set. This causes the subsequent create to fail with
1095 * NT_STATUS_DELETE_PENDING.
1097 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1099 /* Now try opening again for read-only. */
1100 fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1101 SEC_RIGHTS_FILE_READ,
1102 FILE_ATTRIBUTE_DIRECTORY,
1103 NTCREATEX_SHARE_ACCESS_READ|
1104 NTCREATEX_SHARE_ACCESS_WRITE|
1105 NTCREATEX_SHARE_ACCESS_DELETE,
1106 NTCREATEX_DISP_OPEN,
1107 NTCREATEX_OPTIONS_DIRECTORY, 0);
1109 /* Should work. */
1110 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1111 dname, smbcli_errstr(cli1->tree)));
1113 smbcli_close(cli1->tree, fnum1);
1115 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
1117 smbcli_close(cli1->tree, fnum2);
1119 /* See if the file is deleted - for a directory this seems to be true ! */
1120 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1121 SEC_RIGHTS_FILE_READ,
1122 FILE_ATTRIBUTE_DIRECTORY,
1123 NTCREATEX_SHARE_ACCESS_READ|
1124 NTCREATEX_SHARE_ACCESS_WRITE|
1125 NTCREATEX_SHARE_ACCESS_DELETE,
1126 NTCREATEX_DISP_OPEN,
1127 NTCREATEX_OPTIONS_DIRECTORY, 0);
1129 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1131 torture_assert(tctx, fnum1 == -1,
1132 talloc_asprintf(tctx, "open of %s succeeded (should fail)", dname));
1134 return correct;
1137 /* Test 20 ... */
1138 static bool deltest20(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1140 int fnum1 = -1;
1141 int dnum1 = -1;
1142 bool correct = true;
1143 NTSTATUS status;
1145 del_clean_area(cli1, cli2);
1147 /* Test 20 -- non-empty directory hardest to get right... */
1149 if (torture_setting_bool(tctx, "samba3", false)) {
1150 return true;
1153 smbcli_deltree(cli1->tree, dname);
1155 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1156 SEC_FILE_READ_DATA|
1157 SEC_FILE_WRITE_DATA|
1158 SEC_STD_DELETE,
1159 FILE_ATTRIBUTE_DIRECTORY,
1160 NTCREATEX_SHARE_ACCESS_READ|
1161 NTCREATEX_SHARE_ACCESS_WRITE|
1162 NTCREATEX_SHARE_ACCESS_DELETE,
1163 NTCREATEX_DISP_CREATE,
1164 NTCREATEX_OPTIONS_DIRECTORY, 0);
1165 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
1166 dname, smbcli_errstr(cli1->tree)));
1168 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
1169 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1172 char *fullname;
1173 asprintf(&fullname, "\\%s%s", dname, fname);
1174 fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
1175 DENY_NONE);
1176 torture_assert(tctx, fnum1 == -1,
1177 "smbcli_open succeeded, should have "
1178 "failed with NT_STATUS_DELETE_PENDING"
1181 torture_assert_ntstatus_equal(tctx,
1182 smbcli_nt_error(cli1->tree),
1183 NT_STATUS_DELETE_PENDING,
1184 "smbcli_open failed");
1187 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, false);
1188 torture_assert_ntstatus_ok(tctx, status,
1189 "setting delete_on_close on file failed !");
1192 char *fullname;
1193 asprintf(&fullname, "\\%s%s", dname, fname);
1194 fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
1195 DENY_NONE);
1196 torture_assert(tctx, fnum1 != -1,
1197 talloc_asprintf(tctx, "smbcli_open failed: %s\n",
1198 smbcli_errstr(cli1->tree)));
1199 smbcli_close(cli1->tree, fnum1);
1202 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1204 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DIRECTORY_NOT_EMPTY,
1205 "setting delete_on_close failed");
1206 smbcli_close(cli1->tree, dnum1);
1208 return correct;
1211 /* Test 20a ... */
1212 static bool deltest20a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1214 int fnum1 = -1;
1215 int fnum2 = -1;
1216 bool correct = true;
1218 del_clean_area(cli1, cli2);
1220 /* Test 20a. */
1222 /* Ensure the file doesn't already exist. */
1223 smbcli_close(cli1->tree, fnum1);
1224 smbcli_close(cli1->tree, fnum2);
1225 smbcli_setatr(cli1->tree, fname, 0, 0);
1226 smbcli_unlink(cli1->tree, fname);
1228 /* Firstly open and create with all access */
1229 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1230 SEC_RIGHTS_FILE_ALL,
1231 FILE_ATTRIBUTE_NORMAL,
1232 NTCREATEX_SHARE_ACCESS_READ|
1233 NTCREATEX_SHARE_ACCESS_WRITE|
1234 NTCREATEX_SHARE_ACCESS_DELETE,
1235 NTCREATEX_DISP_CREATE,
1236 0, 0);
1237 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1238 fname, smbcli_errstr(cli1->tree)));
1240 /* Next open with all access, but add delete on close. */
1241 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
1242 SEC_RIGHTS_FILE_ALL,
1243 FILE_ATTRIBUTE_NORMAL,
1244 NTCREATEX_SHARE_ACCESS_READ|
1245 NTCREATEX_SHARE_ACCESS_WRITE|
1246 NTCREATEX_SHARE_ACCESS_DELETE,
1247 NTCREATEX_DISP_OPEN,
1248 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1250 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
1251 fname, smbcli_errstr(cli2->tree)));
1253 /* The delete on close bit is *not* reported as being set. */
1254 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
1255 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1257 smbcli_close(cli1->tree, fnum1);
1259 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1261 smbcli_close(cli2->tree, fnum2);
1263 /* See if the file is deleted - should be.... */
1264 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
1265 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1266 fname, smbcli_errstr(cli1->tree)));
1268 return correct;
1271 /* Test 20b ... */
1272 /* This is the delete semantics that the cifsfs client depends on when
1273 * trying to delete an open file on a Windows server. It
1274 * opens a file with initial delete on close set, renames it then closes
1275 * all open handles. The file goes away on Windows.
1278 static bool deltest20b(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1280 int fnum1 = -1;
1281 int fnum2 = -1;
1282 bool correct = true;
1284 del_clean_area(cli1, cli2);
1286 /* Test 20b. */
1288 /* Ensure the file doesn't already exist. */
1289 smbcli_close(cli1->tree, fnum1);
1290 smbcli_close(cli1->tree, fnum2);
1291 smbcli_setatr(cli1->tree, fname, 0, 0);
1292 smbcli_unlink(cli1->tree, fname);
1293 smbcli_setatr(cli1->tree, fname_new, 0, 0);
1294 smbcli_unlink(cli1->tree, fname_new);
1296 /* Firstly open and create with all access */
1297 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1298 SEC_RIGHTS_FILE_ALL,
1299 FILE_ATTRIBUTE_NORMAL,
1300 NTCREATEX_SHARE_ACCESS_READ|
1301 NTCREATEX_SHARE_ACCESS_WRITE|
1302 NTCREATEX_SHARE_ACCESS_DELETE,
1303 NTCREATEX_DISP_CREATE,
1304 0, 0);
1305 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1306 fname, smbcli_errstr(cli1->tree)));
1308 /* And close - just to create the file. */
1309 smbcli_close(cli1->tree, fnum1);
1311 /* Firstly open and create with all access */
1312 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1313 SEC_RIGHTS_FILE_ALL,
1314 FILE_ATTRIBUTE_NORMAL,
1315 NTCREATEX_SHARE_ACCESS_READ|
1316 NTCREATEX_SHARE_ACCESS_WRITE|
1317 NTCREATEX_SHARE_ACCESS_DELETE,
1318 NTCREATEX_DISP_OPEN,
1319 0, 0);
1320 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1321 fname, smbcli_errstr(cli1->tree)));
1323 /* Next open with all access, but add delete on close. */
1324 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
1325 SEC_RIGHTS_FILE_ALL,
1326 FILE_ATTRIBUTE_NORMAL,
1327 NTCREATEX_SHARE_ACCESS_READ|
1328 NTCREATEX_SHARE_ACCESS_WRITE|
1329 NTCREATEX_SHARE_ACCESS_DELETE,
1330 NTCREATEX_DISP_OPEN,
1331 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1333 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
1334 fname, smbcli_errstr(cli2->tree)));
1336 /* The delete on close bit is *not* reported as being set. */
1337 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
1338 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1340 smbcli_close(cli1->tree, fnum1);
1342 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1344 /* Rename the file by handle. */
1347 union smb_setfileinfo sfinfo;
1348 NTSTATUS status;
1350 memset(&sfinfo, '\0', sizeof(sfinfo));
1351 sfinfo.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
1352 sfinfo.generic.in.file.fnum = fnum2;
1353 sfinfo.rename_information.in.root_fid = 0;
1354 /* Don't start the filename with '\\', we get NT_STATUS_NOT_SUPPORTED if so. */
1355 sfinfo.rename_information.in.new_name = fname_new + 1;
1356 sfinfo.rename_information.in.overwrite = 1;
1358 status = smb_raw_setfileinfo(cli2->tree, &sfinfo);
1360 torture_assert_ntstatus_equal(tctx,status,NT_STATUS_OK,talloc_asprintf(tctx, "rename of %s to %s failed (%s)",
1361 fname, fname_new, smbcli_errstr(cli2->tree)));
1364 correct &= check_delete_on_close(tctx, cli2, fnum2, fname_new, false, __location__);
1366 smbcli_close(cli2->tree, fnum2);
1368 /* See if the file is deleted - should be.... */
1369 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
1370 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1371 fname, smbcli_errstr(cli1->tree)));
1372 fnum1 = smbcli_open(cli1->tree, fname_new, O_RDWR, DENY_NONE);
1373 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1374 fname_new, smbcli_errstr(cli1->tree)));
1376 return correct;
1380 /* Test 21 ... */
1381 static bool deltest21(struct torture_context *tctx)
1383 int fnum1 = -1;
1384 struct smbcli_state *cli1;
1385 struct smbcli_state *cli2;
1386 bool correct = true;
1388 if (!torture_open_connection(&cli1, tctx, 0))
1389 return false;
1391 if (!torture_open_connection(&cli2, tctx, 1))
1392 return false;
1394 del_clean_area(cli1, cli2);
1396 /* Test 21 -- Test removal of file after socket close. */
1398 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1399 SEC_RIGHTS_FILE_ALL,
1400 FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
1401 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1403 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
1404 fname, smbcli_errstr(cli1->tree)));
1406 torture_assert_ntstatus_ok(tctx,
1407 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
1408 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
1409 smbcli_errstr(cli1->tree)));
1411 /* Ensure delete on close is set. */
1412 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
1414 /* Now yank the rug from under cli1. */
1415 smbcli_transport_dead(cli1->transport, NT_STATUS_LOCAL_DISCONNECT);
1417 fnum1 = -1;
1419 if (!torture_open_connection(&cli1, tctx, 0)) {
1420 return false;
1423 /* On slow build farm machines it might happen that they are not fast
1424 * enogh to delete the file for this test */
1425 smb_msleep(200);
1427 /* File should not be there. */
1428 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1429 SEC_RIGHTS_FILE_READ,
1430 FILE_ATTRIBUTE_NORMAL,
1431 NTCREATEX_SHARE_ACCESS_READ|
1432 NTCREATEX_SHARE_ACCESS_WRITE|
1433 NTCREATEX_SHARE_ACCESS_DELETE,
1434 NTCREATEX_DISP_OPEN,
1435 0, 0);
1437 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1439 return correct;
1442 /* Test 22 ... */
1445 * Test whether a second *directory* handle inhibits delete if the first has
1446 * del-on-close set and is closed
1448 static bool deltest22(struct torture_context *tctx)
1450 int dnum1 = -1;
1451 int dnum2 = -1;
1452 struct smbcli_state *cli1;
1453 bool correct = true;
1455 if (!torture_open_connection(&cli1, tctx, 0))
1456 return false;
1458 smbcli_deltree(cli1->tree, dname);
1460 torture_assert_ntstatus_ok(
1461 tctx, smbcli_mkdir(cli1->tree, dname),
1462 talloc_asprintf(tctx, "smbcli_mdir failed: (%s)\n",
1463 smbcli_errstr(cli1->tree)));
1465 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1466 SEC_FILE_READ_DATA|
1467 SEC_FILE_WRITE_DATA|
1468 SEC_STD_DELETE,
1469 FILE_ATTRIBUTE_DIRECTORY,
1470 NTCREATEX_SHARE_ACCESS_READ|
1471 NTCREATEX_SHARE_ACCESS_WRITE|
1472 NTCREATEX_SHARE_ACCESS_DELETE,
1473 NTCREATEX_DISP_OPEN,
1474 NTCREATEX_OPTIONS_DIRECTORY, 0);
1476 torture_assert(tctx, dnum1 != -1,
1477 talloc_asprintf(tctx, "open of %s failed: %s!",
1478 dname, smbcli_errstr(cli1->tree)));
1480 dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1481 SEC_FILE_READ_DATA|
1482 SEC_FILE_WRITE_DATA,
1483 FILE_ATTRIBUTE_DIRECTORY,
1484 NTCREATEX_SHARE_ACCESS_READ|
1485 NTCREATEX_SHARE_ACCESS_WRITE|
1486 NTCREATEX_SHARE_ACCESS_DELETE,
1487 NTCREATEX_DISP_OPEN,
1488 NTCREATEX_OPTIONS_DIRECTORY, 0);
1490 torture_assert(tctx, dnum2 != -1,
1491 talloc_asprintf(tctx, "open of %s failed: %s!",
1492 dname, smbcli_errstr(cli1->tree)));
1494 torture_assert_ntstatus_ok(
1495 tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
1496 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
1497 smbcli_errstr(cli1->tree)));
1499 smbcli_close(cli1->tree, dnum1);
1501 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1502 SEC_FILE_READ_DATA|
1503 SEC_FILE_WRITE_DATA|
1504 SEC_STD_DELETE,
1505 FILE_ATTRIBUTE_DIRECTORY,
1506 NTCREATEX_SHARE_ACCESS_READ|
1507 NTCREATEX_SHARE_ACCESS_WRITE|
1508 NTCREATEX_SHARE_ACCESS_DELETE,
1509 NTCREATEX_DISP_OPEN,
1510 NTCREATEX_OPTIONS_DIRECTORY, 0);
1512 torture_assert(tctx, dnum1 == -1,
1513 talloc_asprintf(tctx, "open of %s succeeded!\n",
1514 dname));
1516 CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
1518 smbcli_close(cli1->tree, dnum2);
1519 CHECK_STATUS(cli1, NT_STATUS_OK);
1521 return correct;
1524 /* Test 23 - Second directory open fails when delete is pending. */
1525 static bool deltest23(struct torture_context *tctx,
1526 struct smbcli_state *cli1,
1527 struct smbcli_state *cli2)
1529 int dnum1 = -1;
1530 int dnum2 = -1;
1531 bool correct = true;
1532 NTSTATUS status;
1534 del_clean_area(cli1, cli2);
1536 /* Test 23 -- Basic delete on close for directories. */
1538 /* Open a directory */
1539 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1540 SEC_FILE_READ_DATA|
1541 SEC_FILE_WRITE_DATA|
1542 SEC_STD_DELETE,
1543 FILE_ATTRIBUTE_DIRECTORY,
1544 NTCREATEX_SHARE_ACCESS_READ|
1545 NTCREATEX_SHARE_ACCESS_WRITE|
1546 NTCREATEX_SHARE_ACCESS_DELETE,
1547 NTCREATEX_DISP_CREATE,
1548 NTCREATEX_OPTIONS_DIRECTORY, 0);
1550 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx,
1551 "open of %s failed: %s!",
1552 dname, smbcli_errstr(cli1->tree)));
1554 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false,
1555 __location__);
1557 /* Set delete on close */
1558 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1560 /* Attempt opening the directory again. It should fail. */
1561 dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1562 SEC_FILE_READ_DATA|
1563 SEC_FILE_WRITE_DATA|
1564 SEC_STD_DELETE,
1565 FILE_ATTRIBUTE_DIRECTORY,
1566 NTCREATEX_SHARE_ACCESS_READ|
1567 NTCREATEX_SHARE_ACCESS_WRITE|
1568 NTCREATEX_SHARE_ACCESS_DELETE,
1569 NTCREATEX_DISP_OPEN,
1570 NTCREATEX_OPTIONS_DIRECTORY, 0);
1572 torture_assert(tctx, dnum2 == -1, talloc_asprintf(tctx,
1573 "open of %s succeeded: %s. It should have failed "
1574 "with NT_STATUS_DELETE_PENDING",
1575 dname, smbcli_errstr(cli1->tree)));
1577 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree),
1578 NT_STATUS_DELETE_PENDING, "smbcli_open failed");
1580 return true;
1584 Test delete on close semantics.
1586 struct torture_suite *torture_test_delete(void)
1588 struct torture_suite *suite = torture_suite_create(
1589 talloc_autofree_context(), "delete");
1591 torture_suite_add_2smb_test(suite, "deltest1", deltest1);
1592 torture_suite_add_2smb_test(suite, "deltest2", deltest2);
1593 torture_suite_add_2smb_test(suite, "deltest3", deltest3);
1594 torture_suite_add_2smb_test(suite, "deltest4", deltest4);
1595 torture_suite_add_2smb_test(suite, "deltest5", deltest5);
1596 torture_suite_add_2smb_test(suite, "deltest6", deltest6);
1597 torture_suite_add_2smb_test(suite, "deltest7", deltest7);
1598 torture_suite_add_2smb_test(suite, "deltest8", deltest8);
1599 torture_suite_add_2smb_test(suite, "deltest9", deltest9);
1600 torture_suite_add_2smb_test(suite, "deltest10", deltest10);
1601 torture_suite_add_2smb_test(suite, "deltest11", deltest11);
1602 torture_suite_add_2smb_test(suite, "deltest12", deltest12);
1603 torture_suite_add_2smb_test(suite, "deltest13", deltest13);
1604 torture_suite_add_2smb_test(suite, "deltest14", deltest14);
1605 torture_suite_add_2smb_test(suite, "deltest15", deltest15);
1606 torture_suite_add_2smb_test(suite, "deltest16", deltest16);
1607 torture_suite_add_2smb_test(suite, "deltest17", deltest17);
1608 torture_suite_add_2smb_test(suite, "deltest18", deltest18);
1609 torture_suite_add_2smb_test(suite, "deltest19", deltest19);
1610 torture_suite_add_2smb_test(suite, "deltest20", deltest20);
1611 torture_suite_add_2smb_test(suite, "deltest20a", deltest20a);
1612 torture_suite_add_2smb_test(suite, "deltest20b", deltest20b);
1613 torture_suite_add_simple_test(suite, "deltest21", deltest21);
1614 torture_suite_add_simple_test(suite, "deltest22", deltest22);
1615 torture_suite_add_2smb_test(suite, "deltest23", deltest23);
1617 return suite;