s4:torture:basic: fix abundance of spaces in deltest6
[Samba/gebeck_regimport.git] / source4 / torture / basic / delete.c
blob7a5517940704ec54623e22f5bb69f310cae9267c
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"
29 #include "torture/basic/proto.h"
31 static bool check_delete_on_close(struct torture_context *tctx,
32 struct smbcli_state *cli, int fnum,
33 const char *fname, bool expect_it,
34 const char *where)
36 union smb_search_data data;
37 NTSTATUS status;
39 time_t c_time, a_time, m_time;
40 size_t size;
41 uint16_t mode;
43 status = torture_single_search(cli, tctx,
44 fname,
45 RAW_SEARCH_TRANS2,
46 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
47 FILE_ATTRIBUTE_DIRECTORY,
48 &data);
49 torture_assert_ntstatus_ok(tctx, status,
50 talloc_asprintf(tctx, "single_search failed (%s)", where));
52 if (fnum != -1) {
53 union smb_fileinfo io;
54 int nlink = expect_it ? 0 : 1;
56 io.all_info.level = RAW_FILEINFO_ALL_INFO;
57 io.all_info.in.file.fnum = fnum;
59 status = smb_raw_fileinfo(cli->tree, tctx, &io);
60 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx,
61 "qfileinfo failed (%s)", where));
63 torture_assert(tctx, expect_it == io.all_info.out.delete_pending,
64 talloc_asprintf(tctx,
65 "%s - Expected del_on_close flag %d, qfileinfo/all_info gave %d",
66 where, expect_it, io.all_info.out.delete_pending));
68 torture_assert(tctx, nlink == io.all_info.out.nlink,
69 talloc_asprintf(tctx,
70 "%s - Expected nlink %d, qfileinfo/all_info gave %d",
71 where, nlink, io.all_info.out.nlink));
73 io.standard_info.level = RAW_FILEINFO_STANDARD_INFO;
74 io.standard_info.in.file.fnum = fnum;
76 status = smb_raw_fileinfo(cli->tree, tctx, &io);
77 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
79 torture_assert(tctx, expect_it == io.standard_info.out.delete_pending,
80 talloc_asprintf(tctx, "%s - Expected del_on_close flag %d, qfileinfo/standard_info gave %d\n",
81 where, expect_it, io.standard_info.out.delete_pending));
83 torture_assert(tctx, nlink == io.standard_info.out.nlink,
84 talloc_asprintf(tctx, "%s - Expected nlink %d, qfileinfo/standard_info gave %d",
85 where, nlink, io.all_info.out.nlink));
88 status = smbcli_qpathinfo(cli->tree, fname,
89 &c_time, &a_time, &m_time,
90 &size, &mode);
92 if (expect_it) {
93 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
94 "qpathinfo did not give correct error code");
95 } else {
96 torture_assert_ntstatus_ok(tctx, status,
97 talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
100 return true;
103 #define CHECK_STATUS(_cli, _expected) \
104 torture_assert_ntstatus_equal(tctx, _cli->tree->session->transport->error.e.nt_status, _expected, \
105 "Incorrect status")
107 static const char *fname = "\\delete.file";
108 static const char *fname_new = "\\delete.new";
109 static const char *dname = "\\delete.dir";
111 static void del_clean_area(struct smbcli_state *cli1, struct smbcli_state *cli2)
113 smb_raw_exit(cli1->session);
114 smb_raw_exit(cli2->session);
116 smbcli_deltree(cli1->tree, dname);
117 smbcli_setatr(cli1->tree, fname, 0, 0);
118 smbcli_unlink(cli1->tree, fname);
119 smbcli_setatr(cli1->tree, fname_new, 0, 0);
120 smbcli_unlink(cli1->tree, fname_new);
123 /* Test 1 - this should delete the file on close. */
125 static bool deltest1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
127 int fnum1 = -1;
129 del_clean_area(cli1, cli2);
131 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
132 SEC_RIGHTS_FILE_ALL,
133 FILE_ATTRIBUTE_NORMAL,
134 NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OVERWRITE_IF,
135 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
137 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
138 fname, smbcli_errstr(cli1->tree)));
140 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
141 talloc_asprintf(tctx, "close failed (%s)", smbcli_errstr(cli1->tree)));
143 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
144 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
145 fname));
147 return true;
150 /* Test 2 - this should delete the file on close. */
151 static bool deltest2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
153 int fnum1 = -1;
155 del_clean_area(cli1, cli2);
157 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
158 SEC_RIGHTS_FILE_ALL,
159 FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
160 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
162 torture_assert(tctx, fnum1 != -1,
163 talloc_asprintf(tctx, "open of %s failed (%s)",
164 fname, smbcli_errstr(cli1->tree)));
166 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
167 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
168 smbcli_errstr(cli1->tree)));
170 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
171 talloc_asprintf(tctx, "close failed (%s)",
172 smbcli_errstr(cli1->tree)));
174 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
175 if (fnum1 != -1) {
176 printf("(%s) open of %s succeeded should have been deleted on close !\n",
177 __location__, fname);
178 if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
179 printf("(%s) close failed (%s)\n",
180 __location__, smbcli_errstr(cli1->tree));
181 return false;
183 smbcli_unlink(cli1->tree, fname);
185 return true;
188 /* Test 3 - ... */
189 static bool deltest3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
191 int fnum1 = -1;
192 int fnum2 = -1;
194 del_clean_area(cli1, cli2);
196 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
197 SEC_RIGHTS_FILE_ALL,
198 FILE_ATTRIBUTE_NORMAL,
199 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
200 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
202 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
203 fname, smbcli_errstr(cli1->tree)));
205 /* This should fail with a sharing violation - open for delete is only compatible
206 with SHARE_DELETE. */
208 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
209 SEC_RIGHTS_FILE_READ,
210 FILE_ATTRIBUTE_NORMAL,
211 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
212 NTCREATEX_DISP_OPEN, 0, 0);
214 torture_assert(tctx, fnum2 == -1,
215 talloc_asprintf(tctx, "open - 2 of %s succeeded - should have failed.",
216 fname));
218 /* This should succeed. */
220 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
221 SEC_RIGHTS_FILE_READ,
222 FILE_ATTRIBUTE_NORMAL,
223 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
224 NTCREATEX_DISP_OPEN, 0, 0);
226 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
227 fname, smbcli_errstr(cli1->tree)));
229 torture_assert_ntstatus_ok(tctx,
230 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
231 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
232 smbcli_errstr(cli1->tree)));
234 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
235 talloc_asprintf(tctx, "close 1 failed (%s)",
236 smbcli_errstr(cli1->tree)));
238 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
239 talloc_asprintf(tctx, "close 2 failed (%s)",
240 smbcli_errstr(cli1->tree)));
242 /* This should fail - file should no longer be there. */
244 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
245 if (fnum1 != -1) {
246 printf("(%s) open of %s succeeded should have been deleted on close !\n",
247 __location__, fname);
248 if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
249 printf("(%s) close failed (%s)\n",
250 __location__, smbcli_errstr(cli1->tree));
252 smbcli_unlink(cli1->tree, fname);
253 return false;
255 return true;
258 /* Test 4 ... */
259 static bool deltest4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
261 int fnum1 = -1;
262 int fnum2 = -1;
263 bool correct = true;
265 del_clean_area(cli1, cli2);
267 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
268 SEC_FILE_READ_DATA |
269 SEC_FILE_WRITE_DATA |
270 SEC_STD_DELETE,
271 FILE_ATTRIBUTE_NORMAL,
272 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
273 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
275 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
276 fname, smbcli_errstr(cli1->tree)));
278 /* This should succeed. */
279 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
280 SEC_RIGHTS_FILE_READ,
281 FILE_ATTRIBUTE_NORMAL,
282 NTCREATEX_SHARE_ACCESS_READ |
283 NTCREATEX_SHARE_ACCESS_WRITE |
284 NTCREATEX_SHARE_ACCESS_DELETE,
285 NTCREATEX_DISP_OPEN, 0, 0);
286 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
287 fname, smbcli_errstr(cli1->tree)));
289 torture_assert_ntstatus_ok(tctx,
290 smbcli_close(cli1->tree, fnum2),
291 talloc_asprintf(tctx, "close - 1 failed (%s)",
292 smbcli_errstr(cli1->tree)));
294 torture_assert_ntstatus_ok(tctx,
295 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
296 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
297 smbcli_errstr(cli1->tree)));
299 /* This should fail - no more opens once delete on close set. */
300 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
301 SEC_RIGHTS_FILE_READ,
302 FILE_ATTRIBUTE_NORMAL,
303 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
304 NTCREATEX_DISP_OPEN, 0, 0);
305 torture_assert(tctx, fnum2 == -1,
306 talloc_asprintf(tctx, "open - 3 of %s succeeded ! Should have failed.",
307 fname ));
309 CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
311 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
312 talloc_asprintf(tctx, "close - 2 failed (%s)",
313 smbcli_errstr(cli1->tree)));
315 return correct;
318 /* Test 5 ... */
319 static bool deltest5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
321 int fnum1 = -1;
323 del_clean_area(cli1, cli2);
325 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
326 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
327 fname, smbcli_errstr(cli1->tree)));
329 /* This should fail - only allowed on NT opens with DELETE access. */
331 torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
332 "setting delete_on_close on OpenX file succeeded - should fail !");
334 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
335 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
337 return true;
340 /* Test 6 ... */
341 static bool deltest6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
343 int fnum1 = -1;
345 del_clean_area(cli1, cli2);
347 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
348 SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
349 FILE_ATTRIBUTE_NORMAL,
350 NTCREATEX_SHARE_ACCESS_READ |
351 NTCREATEX_SHARE_ACCESS_WRITE |
352 NTCREATEX_SHARE_ACCESS_DELETE,
353 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
355 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
356 fname, smbcli_errstr(cli1->tree)));
358 /* This should fail - only allowed on NT opens with DELETE access. */
360 torture_assert(tctx,
361 !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
362 "setting delete_on_close on file with no delete access succeeded - should fail !");
364 torture_assert_ntstatus_ok(tctx,
365 smbcli_close(cli1->tree, fnum1),
366 talloc_asprintf(tctx,
367 "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 smb_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 smbcli_close(cli1->tree, dnum2);
1521 CHECK_STATUS(cli1, NT_STATUS_OK);
1523 return correct;
1526 /* Test 23 - Second directory open fails when delete is pending. */
1527 static bool deltest23(struct torture_context *tctx,
1528 struct smbcli_state *cli1,
1529 struct smbcli_state *cli2)
1531 int dnum1 = -1;
1532 int dnum2 = -1;
1533 bool correct = true;
1535 del_clean_area(cli1, cli2);
1537 /* Test 23 -- Basic delete on close for directories. */
1539 /* Open a directory */
1540 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1541 SEC_FILE_READ_DATA|
1542 SEC_FILE_WRITE_DATA|
1543 SEC_STD_DELETE,
1544 FILE_ATTRIBUTE_DIRECTORY,
1545 NTCREATEX_SHARE_ACCESS_READ|
1546 NTCREATEX_SHARE_ACCESS_WRITE|
1547 NTCREATEX_SHARE_ACCESS_DELETE,
1548 NTCREATEX_DISP_CREATE,
1549 NTCREATEX_OPTIONS_DIRECTORY, 0);
1551 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx,
1552 "open of %s failed: %s!",
1553 dname, smbcli_errstr(cli1->tree)));
1555 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false,
1556 __location__);
1558 /* Set delete on close */
1559 (void)smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1561 /* Attempt opening the directory again. It should fail. */
1562 dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1563 SEC_FILE_READ_DATA|
1564 SEC_FILE_WRITE_DATA|
1565 SEC_STD_DELETE,
1566 FILE_ATTRIBUTE_DIRECTORY,
1567 NTCREATEX_SHARE_ACCESS_READ|
1568 NTCREATEX_SHARE_ACCESS_WRITE|
1569 NTCREATEX_SHARE_ACCESS_DELETE,
1570 NTCREATEX_DISP_OPEN,
1571 NTCREATEX_OPTIONS_DIRECTORY, 0);
1573 torture_assert(tctx, dnum2 == -1, talloc_asprintf(tctx,
1574 "open of %s succeeded: %s. It should have failed "
1575 "with NT_STATUS_DELETE_PENDING",
1576 dname, smbcli_errstr(cli1->tree)));
1578 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree),
1579 NT_STATUS_DELETE_PENDING, "smbcli_open failed");
1581 return true;
1585 Test delete on close semantics.
1587 struct torture_suite *torture_test_delete(void)
1589 struct torture_suite *suite = torture_suite_create(
1590 talloc_autofree_context(), "delete");
1592 torture_suite_add_2smb_test(suite, "deltest1", deltest1);
1593 torture_suite_add_2smb_test(suite, "deltest2", deltest2);
1594 torture_suite_add_2smb_test(suite, "deltest3", deltest3);
1595 torture_suite_add_2smb_test(suite, "deltest4", deltest4);
1596 torture_suite_add_2smb_test(suite, "deltest5", deltest5);
1597 torture_suite_add_2smb_test(suite, "deltest6", deltest6);
1598 torture_suite_add_2smb_test(suite, "deltest7", deltest7);
1599 torture_suite_add_2smb_test(suite, "deltest8", deltest8);
1600 torture_suite_add_2smb_test(suite, "deltest9", deltest9);
1601 torture_suite_add_2smb_test(suite, "deltest10", deltest10);
1602 torture_suite_add_2smb_test(suite, "deltest11", deltest11);
1603 torture_suite_add_2smb_test(suite, "deltest12", deltest12);
1604 torture_suite_add_2smb_test(suite, "deltest13", deltest13);
1605 torture_suite_add_2smb_test(suite, "deltest14", deltest14);
1606 torture_suite_add_2smb_test(suite, "deltest15", deltest15);
1607 torture_suite_add_2smb_test(suite, "deltest16", deltest16);
1608 torture_suite_add_2smb_test(suite, "deltest17", deltest17);
1609 torture_suite_add_2smb_test(suite, "deltest18", deltest18);
1610 torture_suite_add_2smb_test(suite, "deltest19", deltest19);
1611 torture_suite_add_2smb_test(suite, "deltest20", deltest20);
1612 torture_suite_add_2smb_test(suite, "deltest20a", deltest20a);
1613 torture_suite_add_2smb_test(suite, "deltest20b", deltest20b);
1614 torture_suite_add_simple_test(suite, "deltest21", deltest21);
1615 torture_suite_add_simple_test(suite, "deltest22", deltest22);
1616 torture_suite_add_2smb_test(suite, "deltest23", deltest23);
1618 return suite;