s3-selftest: Remove some unnecessary comma
[Samba/gebeck_regimport.git] / source4 / torture / basic / delete.c
blobbe538d0e9dda976106cc8821d80bb9c0408784bf
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, "close - 2 failed (%s)",
367 smbcli_errstr(cli1->tree)));
369 return true;
372 /* Test 7 ... */
373 static bool deltest7(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
375 int fnum1 = -1;
376 bool correct = true;
378 del_clean_area(cli1, cli2);
380 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
381 SEC_FILE_READ_DATA |
382 SEC_FILE_WRITE_DATA |
383 SEC_STD_DELETE,
384 FILE_ATTRIBUTE_NORMAL, 0,
385 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
387 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
388 fname, smbcli_errstr(cli1->tree)));
390 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
391 "setting delete_on_close on file failed !");
393 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
395 torture_assert_ntstatus_ok(tctx,
396 smbcli_nt_delete_on_close(cli1->tree, fnum1, false),
397 "unsetting delete_on_close on file failed !");
399 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
401 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
402 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
404 /* This next open should succeed - we reset the flag. */
406 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
407 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
408 fname, smbcli_errstr(cli1->tree)));
410 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
411 talloc_asprintf(tctx, "close - 2 failed (%s)",
412 smbcli_errstr(cli1->tree)));
414 return correct;
417 /* Test 8 ... */
418 static bool deltest8(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
420 int fnum1 = -1;
421 int fnum2 = -1;
422 bool correct = true;
424 del_clean_area(cli1, cli2);
426 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
427 SEC_FILE_READ_DATA|
428 SEC_FILE_WRITE_DATA|
429 SEC_STD_DELETE,
430 FILE_ATTRIBUTE_NORMAL,
431 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
432 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
434 torture_assert(tctx, fnum1 != -1,
435 talloc_asprintf(tctx, "open of %s failed (%s)",
436 fname, smbcli_errstr(cli1->tree)));
438 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
439 SEC_FILE_READ_DATA|
440 SEC_FILE_WRITE_DATA|
441 SEC_STD_DELETE,
442 FILE_ATTRIBUTE_NORMAL,
443 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
444 NTCREATEX_DISP_OPEN, 0, 0);
446 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
447 fname, smbcli_errstr(cli1->tree)));
449 torture_assert_ntstatus_ok(tctx,
450 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
451 "setting delete_on_close on file failed !");
453 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
454 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
456 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
457 talloc_asprintf(tctx, "close - 1 failed (%s)",
458 smbcli_errstr(cli1->tree)));
460 correct &= check_delete_on_close(tctx, cli1, -1, fname, true, __location__);
461 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
463 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
464 talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli2->tree)));
466 /* This should fail.. */
467 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
468 torture_assert(tctx, fnum1 == -1,
469 talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !\n", fname));
471 return correct;
474 /* Test 9 ... */
475 static bool deltest9(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
477 int fnum1 = -1;
479 del_clean_area(cli1, cli2);
481 /* This should fail - we need to set DELETE_ACCESS. */
482 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
483 SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
484 FILE_ATTRIBUTE_NORMAL,
485 NTCREATEX_SHARE_ACCESS_NONE,
486 NTCREATEX_DISP_OVERWRITE_IF,
487 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
489 torture_assert(tctx, fnum1 == -1,
490 talloc_asprintf(tctx, "open of %s succeeded should have failed!",
491 fname));
493 return true;
496 /* Test 10 ... */
497 static bool deltest10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
499 int fnum1 = -1;
501 del_clean_area(cli1, cli2);
503 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
504 SEC_FILE_READ_DATA|
505 SEC_FILE_WRITE_DATA|
506 SEC_STD_DELETE,
507 FILE_ATTRIBUTE_NORMAL,
508 NTCREATEX_SHARE_ACCESS_NONE,
509 NTCREATEX_DISP_OVERWRITE_IF,
510 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
511 torture_assert(tctx, fnum1 != -1,
512 talloc_asprintf(tctx, "open of %s failed (%s)",
513 fname, smbcli_errstr(cli1->tree)));
515 /* This should delete the file. */
516 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
517 talloc_asprintf(tctx, "close failed (%s)",
518 smbcli_errstr(cli1->tree)));
520 /* This should fail.. */
521 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
522 torture_assert(tctx, fnum1 == -1,
523 talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !",
524 fname));
525 return true;
528 /* Test 11 ... */
529 static bool deltest11(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
531 int fnum1 = -1;
532 NTSTATUS status;
534 del_clean_area(cli1, cli2);
536 /* test 11 - does having read only attribute still allow delete on close. */
538 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
539 SEC_RIGHTS_FILE_ALL,
540 FILE_ATTRIBUTE_READONLY,
541 NTCREATEX_SHARE_ACCESS_NONE,
542 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
544 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
545 fname, smbcli_errstr(cli1->tree)));
547 status = smbcli_nt_delete_on_close(cli1->tree, fnum1, true);
549 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
550 talloc_asprintf(tctx, "setting delete_on_close should fail with NT_STATUS_CANNOT_DELETE. Got %s instead)", smbcli_errstr(cli1->tree)));
552 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
553 talloc_asprintf(tctx, "close failed (%s)",
554 smbcli_errstr(cli1->tree)));
556 return true;
559 /* Test 12 ... */
560 static bool deltest12(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
562 int fnum1 = -1;
563 NTSTATUS status;
565 del_clean_area(cli1, cli2);
567 /* test 12 - does having read only attribute still allow delete on
568 * close at time of open. */
570 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
571 SEC_RIGHTS_FILE_ALL,
572 FILE_ATTRIBUTE_READONLY,
573 NTCREATEX_SHARE_ACCESS_DELETE,
574 NTCREATEX_DISP_OVERWRITE_IF,
575 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
577 torture_assert(tctx, fnum1 == -1,
578 talloc_asprintf(tctx, "open of %s succeeded. Should fail with "
579 "NT_STATUS_CANNOT_DELETE.\n", fname));
581 status = smbcli_nt_error(cli1->tree);
582 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
583 talloc_asprintf(tctx, "setting delete_on_close on open should "
584 "fail with NT_STATUS_CANNOT_DELETE. Got %s "
585 "instead)",
586 smbcli_errstr(cli1->tree)));
588 return true;
591 /* Test 13 ... */
592 static bool deltest13(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
594 int fnum1 = -1;
595 int fnum2 = -1;
596 bool correct = true;
598 del_clean_area(cli1, cli2);
600 /* Test 13: Does resetting the delete on close flag affect a second
601 * fd? */
603 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
604 SEC_FILE_READ_DATA|
605 SEC_FILE_WRITE_DATA|
606 SEC_STD_DELETE,
607 FILE_ATTRIBUTE_NORMAL,
608 NTCREATEX_SHARE_ACCESS_READ|
609 NTCREATEX_SHARE_ACCESS_WRITE|
610 NTCREATEX_SHARE_ACCESS_DELETE,
611 NTCREATEX_DISP_OVERWRITE_IF,
612 0, 0);
614 torture_assert(tctx, fnum1 != -1,
615 talloc_asprintf(tctx, "open of %s failed (%s)",
616 fname, smbcli_errstr(cli1->tree)));
618 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
619 SEC_FILE_READ_DATA|
620 SEC_FILE_WRITE_DATA|
621 SEC_STD_DELETE,
622 FILE_ATTRIBUTE_NORMAL,
623 NTCREATEX_SHARE_ACCESS_READ|
624 NTCREATEX_SHARE_ACCESS_WRITE|
625 NTCREATEX_SHARE_ACCESS_DELETE,
626 NTCREATEX_DISP_OPEN, 0, 0);
628 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
629 "open of %s failed (%s)",
630 fname, smbcli_errstr(cli2->tree)));
632 torture_assert_ntstatus_ok(tctx,
633 smbcli_nt_delete_on_close(cli1->tree, fnum1,
634 true),
635 "setting delete_on_close on file failed !");
637 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
638 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
640 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli2->tree, fnum2,
641 false),
642 "setting delete_on_close on file failed !");
644 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
645 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
647 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
648 talloc_asprintf(tctx, "close - 1 failed (%s)",
649 smbcli_errstr(cli1->tree)));
651 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
652 talloc_asprintf(tctx, "close - 2 failed (%s)",
653 smbcli_errstr(cli2->tree)));
655 fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
657 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed!",
658 fname));
660 smbcli_close(cli1->tree, fnum1);
662 return correct;
665 /* Test 14 ... */
666 static bool deltest14(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
668 int dnum1 = -1;
669 bool correct = true;
671 del_clean_area(cli1, cli2);
673 /* Test 14 -- directory */
675 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
676 SEC_FILE_READ_DATA|
677 SEC_FILE_WRITE_DATA|
678 SEC_STD_DELETE,
679 FILE_ATTRIBUTE_DIRECTORY,
680 NTCREATEX_SHARE_ACCESS_READ|
681 NTCREATEX_SHARE_ACCESS_WRITE|
682 NTCREATEX_SHARE_ACCESS_DELETE,
683 NTCREATEX_DISP_CREATE, 0, 0);
684 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
685 dname, smbcli_errstr(cli1->tree)));
687 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
688 torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
689 "setting delete_on_close on file failed !");
690 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, true, __location__);
691 smbcli_close(cli1->tree, dnum1);
693 /* Now it should be gone... */
695 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
696 SEC_FILE_READ_DATA|
697 SEC_FILE_WRITE_DATA|
698 SEC_STD_DELETE,
699 FILE_ATTRIBUTE_DIRECTORY,
700 NTCREATEX_SHARE_ACCESS_READ|
701 NTCREATEX_SHARE_ACCESS_WRITE|
702 NTCREATEX_SHARE_ACCESS_DELETE,
703 NTCREATEX_DISP_OPEN, 0, 0);
704 torture_assert(tctx, dnum1 == -1, "setting delete_on_close on file succeeded !");
706 return correct;
709 /* Test 15 ... */
710 static bool deltest15(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
712 int fnum1 = -1;
713 bool correct = true;
714 int fnum2 = -1;
715 NTSTATUS status;
717 del_clean_area(cli1, cli2);
719 /* Test 15: delete on close under rename */
721 smbcli_setatr(cli1->tree, fname, 0, 0);
722 smbcli_unlink(cli1->tree, fname);
723 smbcli_unlink(cli1->tree, fname_new);
725 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
726 SEC_FILE_READ_DATA,
727 FILE_ATTRIBUTE_NORMAL,
728 NTCREATEX_SHARE_ACCESS_READ|
729 NTCREATEX_SHARE_ACCESS_WRITE|
730 NTCREATEX_SHARE_ACCESS_DELETE,
731 NTCREATEX_DISP_OVERWRITE_IF,
732 0, 0);
734 torture_assert(tctx, fnum1 != -1,
735 talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
737 status = smbcli_rename(cli2->tree, fname, fname_new);
739 torture_assert_ntstatus_ok(tctx, status, "renaming failed!");
741 fnum2 = smbcli_nt_create_full(cli2->tree, fname_new, 0,
742 SEC_GENERIC_ALL,
743 FILE_ATTRIBUTE_NORMAL,
744 NTCREATEX_SHARE_ACCESS_READ|
745 NTCREATEX_SHARE_ACCESS_WRITE|
746 NTCREATEX_SHARE_ACCESS_DELETE,
747 NTCREATEX_DISP_OVERWRITE_IF,
748 0, 0);
750 torture_assert(tctx, fnum2 != -1,
751 talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
752 fname_new, smbcli_errstr(cli1->tree)));
754 status = smbcli_nt_delete_on_close(cli2->tree, fnum2, true);
756 torture_assert_ntstatus_ok(tctx, status,
757 "setting delete_on_close on file failed !");
759 smbcli_close(cli2->tree, fnum2);
761 /* The file should be around under the new name, there's a second
762 * handle open */
764 correct &= check_delete_on_close(tctx, cli1, fnum1, fname_new, true, __location__);
766 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
767 SEC_GENERIC_ALL,
768 FILE_ATTRIBUTE_NORMAL,
769 NTCREATEX_SHARE_ACCESS_READ|
770 NTCREATEX_SHARE_ACCESS_WRITE|
771 NTCREATEX_SHARE_ACCESS_DELETE,
772 NTCREATEX_DISP_OVERWRITE_IF,
773 0, 0);
775 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
776 fname, smbcli_errstr(cli1->tree)));
778 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
780 smbcli_close(cli2->tree, fnum2);
781 smbcli_close(cli1->tree, fnum1);
783 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
784 SEC_FILE_READ_EA,
785 FILE_ATTRIBUTE_NORMAL,
786 NTCREATEX_SHARE_ACCESS_READ|
787 NTCREATEX_SHARE_ACCESS_WRITE|
788 NTCREATEX_SHARE_ACCESS_DELETE,
789 NTCREATEX_DISP_OPEN,
790 0, 0);
792 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
793 fname, smbcli_errstr(cli1->tree)));
795 smbcli_close(cli1->tree, fnum1);
797 fnum1 = smbcli_nt_create_full(cli1->tree, fname_new, 0,
798 SEC_FILE_READ_EA,
799 FILE_ATTRIBUTE_NORMAL,
800 NTCREATEX_SHARE_ACCESS_READ|
801 NTCREATEX_SHARE_ACCESS_WRITE|
802 NTCREATEX_SHARE_ACCESS_DELETE,
803 NTCREATEX_DISP_OPEN,
804 0, 0);
806 torture_assert(tctx, fnum1 == -1,
807 "smbcli_open succeeded, should have "
808 "failed");
810 return correct;
813 /* Test 16 ... */
814 static bool deltest16(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
816 int fnum1 = -1;
817 int fnum2 = -1;
818 bool correct = true;
820 del_clean_area(cli1, cli2);
822 /* Test 16. */
824 /* Ensure the file doesn't already exist. */
825 smbcli_close(cli1->tree, fnum1);
826 smbcli_close(cli1->tree, fnum2);
827 smbcli_setatr(cli1->tree, fname, 0, 0);
828 smbcli_unlink(cli1->tree, fname);
830 /* Firstly create with all access, but delete on close. */
831 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
832 SEC_RIGHTS_FILE_ALL,
833 FILE_ATTRIBUTE_NORMAL,
834 NTCREATEX_SHARE_ACCESS_READ|
835 NTCREATEX_SHARE_ACCESS_WRITE|
836 NTCREATEX_SHARE_ACCESS_DELETE,
837 NTCREATEX_DISP_CREATE,
838 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
840 torture_assert (tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
842 /* The delete on close bit is *not* reported as being set. */
843 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
845 /* The delete on close bit is *not* reported as being set. */
846 correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
847 correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
849 /* Now try opening again for read-only. */
850 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
851 SEC_RIGHTS_FILE_READ,
852 FILE_ATTRIBUTE_NORMAL,
853 NTCREATEX_SHARE_ACCESS_READ|
854 NTCREATEX_SHARE_ACCESS_WRITE|
855 NTCREATEX_SHARE_ACCESS_DELETE,
856 NTCREATEX_DISP_OPEN,
857 0, 0);
859 /* Should work. */
860 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
861 fname, smbcli_errstr(cli1->tree)));
863 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
864 correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
865 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
866 correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
868 smbcli_close(cli1->tree, fnum1);
870 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
871 correct &= check_delete_on_close(tctx, cli2, -1, fname, true, __location__);
873 smbcli_close(cli2->tree, fnum2);
875 /* And the file should be deleted ! */
876 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
877 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
878 fname));
880 return correct;
883 /* Test 17 ... */
884 static bool deltest17(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
886 int fnum1 = -1;
887 int fnum2 = -1;
888 bool correct = true;
890 del_clean_area(cli1, cli2);
892 /* Test 17. */
894 /* Ensure the file doesn't already exist. */
895 smbcli_close(cli1->tree, fnum1);
896 smbcli_close(cli1->tree, fnum2);
897 smbcli_setatr(cli1->tree, fname, 0, 0);
898 smbcli_unlink(cli1->tree, fname);
900 /* Firstly open and create with all access */
901 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
902 SEC_RIGHTS_FILE_ALL,
903 FILE_ATTRIBUTE_NORMAL,
904 NTCREATEX_SHARE_ACCESS_READ|
905 NTCREATEX_SHARE_ACCESS_WRITE|
906 NTCREATEX_SHARE_ACCESS_DELETE,
907 NTCREATEX_DISP_CREATE,
908 0, 0);
909 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
910 fname, smbcli_errstr(cli1->tree)));
912 /* And close - just to create the file. */
913 smbcli_close(cli1->tree, fnum1);
915 /* Next open with all access, but add delete on close. */
916 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
917 SEC_RIGHTS_FILE_ALL,
918 FILE_ATTRIBUTE_NORMAL,
919 NTCREATEX_SHARE_ACCESS_READ|
920 NTCREATEX_SHARE_ACCESS_WRITE|
921 NTCREATEX_SHARE_ACCESS_DELETE,
922 NTCREATEX_DISP_OPEN,
923 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
925 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
926 fname, smbcli_errstr(cli1->tree)));
928 /* The delete on close bit is *not* reported as being set. */
929 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
931 /* Now try opening again for read-only. */
932 fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
933 SEC_RIGHTS_FILE_READ|
934 SEC_STD_DELETE,
935 FILE_ATTRIBUTE_NORMAL,
936 NTCREATEX_SHARE_ACCESS_READ|
937 NTCREATEX_SHARE_ACCESS_WRITE|
938 NTCREATEX_SHARE_ACCESS_DELETE,
939 NTCREATEX_DISP_OPEN,
940 0, 0);
942 /* Should work. */
943 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
944 fname, smbcli_errstr(cli1->tree)));
946 /* still not reported as being set on either */
947 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
948 correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
950 smbcli_close(cli1->tree, fnum1);
952 /* After the first close, the files has the delete on close bit set. */
953 correct &= check_delete_on_close(tctx, cli1, fnum2, fname, true, __location__);
955 smbcli_close(cli1->tree, fnum2);
957 /* Make sure the file has been deleted */
958 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
959 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s failed (should succeed) - %s",
960 fname, smbcli_errstr(cli1->tree)));
962 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
964 return correct;
967 /* Test 18 ... */
968 static bool deltest18(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
970 int fnum1 = -1;
971 int fnum2 = -1;
972 bool correct = true;
974 del_clean_area(cli1, cli2);
976 /* Test 18. With directories. */
978 /* Ensure the file doesn't already exist. */
979 smbcli_close(cli1->tree, fnum1);
980 smbcli_close(cli1->tree, fnum2);
982 smbcli_deltree(cli1->tree, dname);
984 /* Firstly create with all access, but delete on close. */
985 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
986 SEC_FILE_READ_DATA|
987 SEC_FILE_WRITE_DATA|
988 SEC_STD_DELETE,
989 FILE_ATTRIBUTE_DIRECTORY,
990 NTCREATEX_SHARE_ACCESS_READ|
991 NTCREATEX_SHARE_ACCESS_WRITE|
992 NTCREATEX_SHARE_ACCESS_DELETE,
993 NTCREATEX_DISP_CREATE,
994 NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
996 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
997 dname, smbcli_errstr(cli1->tree)));
1000 * The delete on close bit is *not* reported as being set.
1001 * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
1002 * close as being set. This causes the subsequent create to fail with
1003 * NT_STATUS_DELETE_PENDING.
1005 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1007 /* Now try opening again for read-only. */
1008 fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1009 SEC_RIGHTS_FILE_READ,
1010 FILE_ATTRIBUTE_DIRECTORY,
1011 NTCREATEX_SHARE_ACCESS_READ|
1012 NTCREATEX_SHARE_ACCESS_WRITE|
1013 NTCREATEX_SHARE_ACCESS_DELETE,
1014 NTCREATEX_DISP_OPEN,
1015 NTCREATEX_OPTIONS_DIRECTORY, 0);
1018 /* Should work. */
1019 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1020 dname, smbcli_errstr(cli1->tree)));
1022 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1023 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, false, __location__);
1025 smbcli_close(cli1->tree, fnum1);
1027 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
1029 smbcli_close(cli1->tree, fnum2);
1031 /* And the directory should be deleted ! */
1032 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1033 SEC_RIGHTS_FILE_READ,
1034 FILE_ATTRIBUTE_DIRECTORY,
1035 NTCREATEX_SHARE_ACCESS_READ|
1036 NTCREATEX_SHARE_ACCESS_WRITE|
1037 NTCREATEX_SHARE_ACCESS_DELETE,
1038 NTCREATEX_DISP_OPEN,
1039 NTCREATEX_OPTIONS_DIRECTORY, 0);
1040 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
1041 dname));
1043 return correct;
1046 /* Test 19 ... */
1047 static bool deltest19(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1049 int fnum1 = -1;
1050 int fnum2 = -1;
1051 bool correct = true;
1053 del_clean_area(cli1, cli2);
1055 /* Test 19. */
1057 smbcli_deltree(cli1->tree, dname);
1059 /* Firstly open and create with all access */
1060 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1061 SEC_FILE_READ_DATA|
1062 SEC_FILE_WRITE_DATA|
1063 SEC_STD_DELETE,
1064 FILE_ATTRIBUTE_DIRECTORY,
1065 NTCREATEX_SHARE_ACCESS_READ|
1066 NTCREATEX_SHARE_ACCESS_WRITE|
1067 NTCREATEX_SHARE_ACCESS_DELETE,
1068 NTCREATEX_DISP_CREATE,
1069 NTCREATEX_OPTIONS_DIRECTORY, 0);
1071 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1072 dname, smbcli_errstr(cli1->tree)));
1074 /* And close - just to create the directory. */
1075 smbcli_close(cli1->tree, fnum1);
1077 /* Next open with all access, but add delete on close. */
1078 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1079 SEC_FILE_READ_DATA|
1080 SEC_FILE_WRITE_DATA|
1081 SEC_STD_DELETE,
1082 FILE_ATTRIBUTE_DIRECTORY,
1083 NTCREATEX_SHARE_ACCESS_READ|
1084 NTCREATEX_SHARE_ACCESS_WRITE|
1085 NTCREATEX_SHARE_ACCESS_DELETE,
1086 NTCREATEX_DISP_OPEN,
1087 NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1089 torture_assert(tctx, fnum1 != -1,
1090 talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
1093 * The delete on close bit is *not* reported as being set.
1094 * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
1095 * close as being set. This causes the subsequent create to fail with
1096 * NT_STATUS_DELETE_PENDING.
1098 correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
1100 /* Now try opening again for read-only. */
1101 fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1102 SEC_RIGHTS_FILE_READ,
1103 FILE_ATTRIBUTE_DIRECTORY,
1104 NTCREATEX_SHARE_ACCESS_READ|
1105 NTCREATEX_SHARE_ACCESS_WRITE|
1106 NTCREATEX_SHARE_ACCESS_DELETE,
1107 NTCREATEX_DISP_OPEN,
1108 NTCREATEX_OPTIONS_DIRECTORY, 0);
1110 /* Should work. */
1111 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1112 dname, smbcli_errstr(cli1->tree)));
1114 smbcli_close(cli1->tree, fnum1);
1116 correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
1118 smbcli_close(cli1->tree, fnum2);
1120 /* See if the file is deleted - for a directory this seems to be true ! */
1121 fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1122 SEC_RIGHTS_FILE_READ,
1123 FILE_ATTRIBUTE_DIRECTORY,
1124 NTCREATEX_SHARE_ACCESS_READ|
1125 NTCREATEX_SHARE_ACCESS_WRITE|
1126 NTCREATEX_SHARE_ACCESS_DELETE,
1127 NTCREATEX_DISP_OPEN,
1128 NTCREATEX_OPTIONS_DIRECTORY, 0);
1130 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1132 torture_assert(tctx, fnum1 == -1,
1133 talloc_asprintf(tctx, "open of %s succeeded (should fail)", dname));
1135 return correct;
1138 /* Test 20 ... */
1139 static bool deltest20(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1141 int fnum1 = -1;
1142 int dnum1 = -1;
1143 bool correct = true;
1144 NTSTATUS status;
1146 del_clean_area(cli1, cli2);
1148 /* Test 20 -- non-empty directory hardest to get right... */
1150 if (torture_setting_bool(tctx, "samba3", false)) {
1151 return true;
1154 smbcli_deltree(cli1->tree, dname);
1156 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1157 SEC_FILE_READ_DATA|
1158 SEC_FILE_WRITE_DATA|
1159 SEC_STD_DELETE,
1160 FILE_ATTRIBUTE_DIRECTORY,
1161 NTCREATEX_SHARE_ACCESS_READ|
1162 NTCREATEX_SHARE_ACCESS_WRITE|
1163 NTCREATEX_SHARE_ACCESS_DELETE,
1164 NTCREATEX_DISP_CREATE,
1165 NTCREATEX_OPTIONS_DIRECTORY, 0);
1166 torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
1167 dname, smbcli_errstr(cli1->tree)));
1169 correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
1170 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1173 char *fullname;
1174 asprintf(&fullname, "\\%s%s", dname, fname);
1175 fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
1176 DENY_NONE);
1177 torture_assert(tctx, fnum1 == -1,
1178 "smbcli_open succeeded, should have "
1179 "failed with NT_STATUS_DELETE_PENDING"
1182 torture_assert_ntstatus_equal(tctx,
1183 smbcli_nt_error(cli1->tree),
1184 NT_STATUS_DELETE_PENDING,
1185 "smbcli_open failed");
1188 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, false);
1189 torture_assert_ntstatus_ok(tctx, status,
1190 "setting delete_on_close on file failed !");
1193 char *fullname;
1194 asprintf(&fullname, "\\%s%s", dname, fname);
1195 fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
1196 DENY_NONE);
1197 torture_assert(tctx, fnum1 != -1,
1198 talloc_asprintf(tctx, "smbcli_open failed: %s\n",
1199 smbcli_errstr(cli1->tree)));
1200 smbcli_close(cli1->tree, fnum1);
1203 status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
1205 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DIRECTORY_NOT_EMPTY,
1206 "setting delete_on_close failed");
1207 smbcli_close(cli1->tree, dnum1);
1209 return correct;
1212 /* Test 20a ... */
1213 static bool deltest20a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1215 int fnum1 = -1;
1216 int fnum2 = -1;
1217 bool correct = true;
1219 del_clean_area(cli1, cli2);
1221 /* Test 20a. */
1223 /* Ensure the file doesn't already exist. */
1224 smbcli_close(cli1->tree, fnum1);
1225 smbcli_close(cli1->tree, fnum2);
1226 smbcli_setatr(cli1->tree, fname, 0, 0);
1227 smbcli_unlink(cli1->tree, fname);
1229 /* Firstly open and create with all access */
1230 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1231 SEC_RIGHTS_FILE_ALL,
1232 FILE_ATTRIBUTE_NORMAL,
1233 NTCREATEX_SHARE_ACCESS_READ|
1234 NTCREATEX_SHARE_ACCESS_WRITE|
1235 NTCREATEX_SHARE_ACCESS_DELETE,
1236 NTCREATEX_DISP_CREATE,
1237 0, 0);
1238 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1239 fname, smbcli_errstr(cli1->tree)));
1241 /* Next open with all access, but add delete on close. */
1242 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
1243 SEC_RIGHTS_FILE_ALL,
1244 FILE_ATTRIBUTE_NORMAL,
1245 NTCREATEX_SHARE_ACCESS_READ|
1246 NTCREATEX_SHARE_ACCESS_WRITE|
1247 NTCREATEX_SHARE_ACCESS_DELETE,
1248 NTCREATEX_DISP_OPEN,
1249 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1251 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
1252 fname, smbcli_errstr(cli2->tree)));
1254 /* The delete on close bit is *not* reported as being set. */
1255 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
1256 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1258 smbcli_close(cli1->tree, fnum1);
1260 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1262 smbcli_close(cli2->tree, fnum2);
1264 /* See if the file is deleted - should be.... */
1265 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
1266 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1267 fname, smbcli_errstr(cli1->tree)));
1269 return correct;
1272 /* Test 20b ... */
1273 /* This is the delete semantics that the cifsfs client depends on when
1274 * trying to delete an open file on a Windows server. It
1275 * opens a file with initial delete on close set, renames it then closes
1276 * all open handles. The file goes away on Windows.
1279 static bool deltest20b(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
1281 int fnum1 = -1;
1282 int fnum2 = -1;
1283 bool correct = true;
1285 del_clean_area(cli1, cli2);
1287 /* Test 20b. */
1289 /* Ensure the file doesn't already exist. */
1290 smbcli_close(cli1->tree, fnum1);
1291 smbcli_close(cli1->tree, fnum2);
1292 smbcli_setatr(cli1->tree, fname, 0, 0);
1293 smbcli_unlink(cli1->tree, fname);
1294 smbcli_setatr(cli1->tree, fname_new, 0, 0);
1295 smbcli_unlink(cli1->tree, fname_new);
1297 /* Firstly open and create with all access */
1298 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1299 SEC_RIGHTS_FILE_ALL,
1300 FILE_ATTRIBUTE_NORMAL,
1301 NTCREATEX_SHARE_ACCESS_READ|
1302 NTCREATEX_SHARE_ACCESS_WRITE|
1303 NTCREATEX_SHARE_ACCESS_DELETE,
1304 NTCREATEX_DISP_CREATE,
1305 0, 0);
1306 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1307 fname, smbcli_errstr(cli1->tree)));
1309 /* And close - just to create the file. */
1310 smbcli_close(cli1->tree, fnum1);
1312 /* Firstly open and create with all access */
1313 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1314 SEC_RIGHTS_FILE_ALL,
1315 FILE_ATTRIBUTE_NORMAL,
1316 NTCREATEX_SHARE_ACCESS_READ|
1317 NTCREATEX_SHARE_ACCESS_WRITE|
1318 NTCREATEX_SHARE_ACCESS_DELETE,
1319 NTCREATEX_DISP_OPEN,
1320 0, 0);
1321 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
1322 fname, smbcli_errstr(cli1->tree)));
1324 /* Next open with all access, but add delete on close. */
1325 fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
1326 SEC_RIGHTS_FILE_ALL,
1327 FILE_ATTRIBUTE_NORMAL,
1328 NTCREATEX_SHARE_ACCESS_READ|
1329 NTCREATEX_SHARE_ACCESS_WRITE|
1330 NTCREATEX_SHARE_ACCESS_DELETE,
1331 NTCREATEX_DISP_OPEN,
1332 NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
1334 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
1335 fname, smbcli_errstr(cli2->tree)));
1337 /* The delete on close bit is *not* reported as being set. */
1338 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
1339 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1341 smbcli_close(cli1->tree, fnum1);
1343 correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
1345 /* Rename the file by handle. */
1348 union smb_setfileinfo sfinfo;
1349 NTSTATUS status;
1351 memset(&sfinfo, '\0', sizeof(sfinfo));
1352 sfinfo.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
1353 sfinfo.generic.in.file.fnum = fnum2;
1354 sfinfo.rename_information.in.root_fid = 0;
1355 /* Don't start the filename with '\\', we get NT_STATUS_NOT_SUPPORTED if so. */
1356 sfinfo.rename_information.in.new_name = fname_new + 1;
1357 sfinfo.rename_information.in.overwrite = 1;
1359 status = smb_raw_setfileinfo(cli2->tree, &sfinfo);
1361 torture_assert_ntstatus_equal(tctx,status,NT_STATUS_OK,talloc_asprintf(tctx, "rename of %s to %s failed (%s)",
1362 fname, fname_new, smbcli_errstr(cli2->tree)));
1365 correct &= check_delete_on_close(tctx, cli2, fnum2, fname_new, false, __location__);
1367 smbcli_close(cli2->tree, fnum2);
1369 /* See if the file is deleted - should be.... */
1370 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
1371 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1372 fname, smbcli_errstr(cli1->tree)));
1373 fnum1 = smbcli_open(cli1->tree, fname_new, O_RDWR, DENY_NONE);
1374 torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
1375 fname_new, smbcli_errstr(cli1->tree)));
1377 return correct;
1381 /* Test 21 ... */
1382 static bool deltest21(struct torture_context *tctx)
1384 int fnum1 = -1;
1385 struct smbcli_state *cli1;
1386 struct smbcli_state *cli2;
1387 bool correct = true;
1389 if (!torture_open_connection(&cli1, tctx, 0))
1390 return false;
1392 if (!torture_open_connection(&cli2, tctx, 1))
1393 return false;
1395 del_clean_area(cli1, cli2);
1397 /* Test 21 -- Test removal of file after socket close. */
1399 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1400 SEC_RIGHTS_FILE_ALL,
1401 FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
1402 NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1404 torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
1405 fname, smbcli_errstr(cli1->tree)));
1407 torture_assert_ntstatus_ok(tctx,
1408 smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
1409 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
1410 smbcli_errstr(cli1->tree)));
1412 /* Ensure delete on close is set. */
1413 correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
1415 /* Now yank the rug from under cli1. */
1416 smbcli_transport_dead(cli1->transport, NT_STATUS_LOCAL_DISCONNECT);
1418 fnum1 = -1;
1420 if (!torture_open_connection(&cli1, tctx, 0)) {
1421 return false;
1424 /* On slow build farm machines it might happen that they are not fast
1425 * enogh to delete the file for this test */
1426 smb_msleep(200);
1428 /* File should not be there. */
1429 fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1430 SEC_RIGHTS_FILE_READ,
1431 FILE_ATTRIBUTE_NORMAL,
1432 NTCREATEX_SHARE_ACCESS_READ|
1433 NTCREATEX_SHARE_ACCESS_WRITE|
1434 NTCREATEX_SHARE_ACCESS_DELETE,
1435 NTCREATEX_DISP_OPEN,
1436 0, 0);
1438 CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1440 return correct;
1443 /* Test 22 ... */
1446 * Test whether a second *directory* handle inhibits delete if the first has
1447 * del-on-close set and is closed
1449 static bool deltest22(struct torture_context *tctx)
1451 int dnum1 = -1;
1452 int dnum2 = -1;
1453 struct smbcli_state *cli1;
1454 bool correct = true;
1456 if (!torture_open_connection(&cli1, tctx, 0))
1457 return false;
1459 smbcli_deltree(cli1->tree, dname);
1461 torture_assert_ntstatus_ok(
1462 tctx, smbcli_mkdir(cli1->tree, dname),
1463 talloc_asprintf(tctx, "smbcli_mdir failed: (%s)\n",
1464 smbcli_errstr(cli1->tree)));
1466 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1467 SEC_FILE_READ_DATA|
1468 SEC_FILE_WRITE_DATA|
1469 SEC_STD_DELETE,
1470 FILE_ATTRIBUTE_DIRECTORY,
1471 NTCREATEX_SHARE_ACCESS_READ|
1472 NTCREATEX_SHARE_ACCESS_WRITE|
1473 NTCREATEX_SHARE_ACCESS_DELETE,
1474 NTCREATEX_DISP_OPEN,
1475 NTCREATEX_OPTIONS_DIRECTORY, 0);
1477 torture_assert(tctx, dnum1 != -1,
1478 talloc_asprintf(tctx, "open of %s failed: %s!",
1479 dname, smbcli_errstr(cli1->tree)));
1481 dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
1482 SEC_FILE_READ_DATA|
1483 SEC_FILE_WRITE_DATA,
1484 FILE_ATTRIBUTE_DIRECTORY,
1485 NTCREATEX_SHARE_ACCESS_READ|
1486 NTCREATEX_SHARE_ACCESS_WRITE|
1487 NTCREATEX_SHARE_ACCESS_DELETE,
1488 NTCREATEX_DISP_OPEN,
1489 NTCREATEX_OPTIONS_DIRECTORY, 0);
1491 torture_assert(tctx, dnum2 != -1,
1492 talloc_asprintf(tctx, "open of %s failed: %s!",
1493 dname, smbcli_errstr(cli1->tree)));
1495 torture_assert_ntstatus_ok(
1496 tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
1497 talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
1498 smbcli_errstr(cli1->tree)));
1500 smbcli_close(cli1->tree, dnum1);
1502 dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
1503 SEC_FILE_READ_DATA|
1504 SEC_FILE_WRITE_DATA|
1505 SEC_STD_DELETE,
1506 FILE_ATTRIBUTE_DIRECTORY,
1507 NTCREATEX_SHARE_ACCESS_READ|
1508 NTCREATEX_SHARE_ACCESS_WRITE|
1509 NTCREATEX_SHARE_ACCESS_DELETE,
1510 NTCREATEX_DISP_OPEN,
1511 NTCREATEX_OPTIONS_DIRECTORY, 0);
1513 torture_assert(tctx, dnum1 == -1,
1514 talloc_asprintf(tctx, "open of %s succeeded!\n",
1515 dname));
1517 CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
1519 smbcli_close(cli1->tree, dnum2);
1520 CHECK_STATUS(cli1, NT_STATUS_OK);
1522 return correct;
1525 /* Test 23 - Second directory open fails when delete is pending. */
1526 static bool deltest23(struct torture_context *tctx,
1527 struct smbcli_state *cli1,
1528 struct smbcli_state *cli2)
1530 int dnum1 = -1;
1531 int dnum2 = -1;
1532 bool correct = true;
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 (void)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;