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/>.
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
,
36 union smb_search_data data
;
39 time_t c_time
, a_time
, m_time
;
43 status
= torture_single_search(cli
, tctx
,
46 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
,
47 FILE_ATTRIBUTE_DIRECTORY
,
49 torture_assert_ntstatus_ok(tctx
, status
,
50 talloc_asprintf(tctx
, "single_search failed (%s)", where
));
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
,
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
,
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
,
93 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_DELETE_PENDING
,
94 "qpathinfo did not give correct error code");
96 torture_assert_ntstatus_ok(tctx
, status
,
97 talloc_asprintf(tctx
, "qpathinfo failed (%s)", where
));
103 #define CHECK_STATUS(_cli, _expected) \
104 torture_assert_ntstatus_equal(tctx, _cli->tree->session->transport->error.e.nt_status, _expected, \
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
)
129 del_clean_area(cli1
, cli2
);
131 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
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)",
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
)
155 del_clean_area(cli1
, cli2
);
157 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
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
);
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
));
183 smbcli_unlink(cli1
->tree
, fname
);
189 static bool deltest3(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
194 del_clean_area(cli1
, cli2
);
196 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
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.",
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
);
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
);
259 static bool deltest4(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
265 del_clean_area(cli1
, cli2
);
267 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
269 SEC_FILE_WRITE_DATA
|
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.",
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
)));
319 static bool deltest5(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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
)));
341 static bool deltest6(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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. */
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
)));
374 static bool deltest7(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
379 del_clean_area(cli1
, cli2
);
381 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
383 SEC_FILE_WRITE_DATA
|
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
)));
419 static bool deltest8(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
425 del_clean_area(cli1
, cli2
);
427 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
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,
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
));
476 static bool deltest9(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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!",
498 static bool deltest10(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
502 del_clean_area(cli1
, cli2
);
504 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
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 !",
530 static bool deltest11(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
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
)));
561 static bool deltest12(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
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 "
587 smbcli_errstr(cli1
->tree
)));
593 static bool deltest13(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
599 del_clean_area(cli1
, cli2
);
601 /* Test 13: Does resetting the delete on close flag affect a second
604 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
608 FILE_ATTRIBUTE_NORMAL
,
609 NTCREATEX_SHARE_ACCESS_READ
|
610 NTCREATEX_SHARE_ACCESS_WRITE
|
611 NTCREATEX_SHARE_ACCESS_DELETE
,
612 NTCREATEX_DISP_OVERWRITE_IF
,
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,
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
,
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
,
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!",
661 smbcli_close(cli1
->tree
, fnum1
);
667 static bool deltest14(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
672 del_clean_area(cli1
, cli2
);
674 /* Test 14 -- directory */
676 dnum1
= smbcli_nt_create_full(cli1
->tree
, dname
, 0,
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,
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 !");
711 static bool deltest15(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
728 FILE_ATTRIBUTE_NORMAL
,
729 NTCREATEX_SHARE_ACCESS_READ
|
730 NTCREATEX_SHARE_ACCESS_WRITE
|
731 NTCREATEX_SHARE_ACCESS_DELETE
,
732 NTCREATEX_DISP_OVERWRITE_IF
,
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,
744 FILE_ATTRIBUTE_NORMAL
,
745 NTCREATEX_SHARE_ACCESS_READ
|
746 NTCREATEX_SHARE_ACCESS_WRITE
|
747 NTCREATEX_SHARE_ACCESS_DELETE
,
748 NTCREATEX_DISP_OVERWRITE_IF
,
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
765 correct
&= check_delete_on_close(tctx
, cli1
, fnum1
, fname_new
, true, __location__
);
767 fnum2
= smbcli_nt_create_full(cli2
->tree
, fname
, 0,
769 FILE_ATTRIBUTE_NORMAL
,
770 NTCREATEX_SHARE_ACCESS_READ
|
771 NTCREATEX_SHARE_ACCESS_WRITE
|
772 NTCREATEX_SHARE_ACCESS_DELETE
,
773 NTCREATEX_DISP_OVERWRITE_IF
,
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,
786 FILE_ATTRIBUTE_NORMAL
,
787 NTCREATEX_SHARE_ACCESS_READ
|
788 NTCREATEX_SHARE_ACCESS_WRITE
|
789 NTCREATEX_SHARE_ACCESS_DELETE
,
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,
800 FILE_ATTRIBUTE_NORMAL
,
801 NTCREATEX_SHARE_ACCESS_READ
|
802 NTCREATEX_SHARE_ACCESS_WRITE
|
803 NTCREATEX_SHARE_ACCESS_DELETE
,
807 torture_assert(tctx
, fnum1
== -1,
808 "smbcli_open succeeded, should have "
815 static bool deltest16(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
821 del_clean_area(cli1
, cli2
);
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,
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
,
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)",
885 static bool deltest17(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
891 del_clean_area(cli1
, cli2
);
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,
904 FILE_ATTRIBUTE_NORMAL
,
905 NTCREATEX_SHARE_ACCESS_READ
|
906 NTCREATEX_SHARE_ACCESS_WRITE
|
907 NTCREATEX_SHARE_ACCESS_DELETE
,
908 NTCREATEX_DISP_CREATE
,
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,
919 FILE_ATTRIBUTE_NORMAL
,
920 NTCREATEX_SHARE_ACCESS_READ
|
921 NTCREATEX_SHARE_ACCESS_WRITE
|
922 NTCREATEX_SHARE_ACCESS_DELETE
,
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
|
936 FILE_ATTRIBUTE_NORMAL
,
937 NTCREATEX_SHARE_ACCESS_READ
|
938 NTCREATEX_SHARE_ACCESS_WRITE
|
939 NTCREATEX_SHARE_ACCESS_DELETE
,
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
);
969 static bool deltest18(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
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);
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)",
1048 static bool deltest19(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
1052 bool correct
= true;
1054 del_clean_area(cli1
, cli2
);
1058 smbcli_deltree(cli1
->tree
, dname
);
1060 /* Firstly open and create with all access */
1061 fnum1
= smbcli_nt_create_full(cli1
->tree
, dname
, 0,
1063 SEC_FILE_WRITE_DATA
|
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,
1081 SEC_FILE_WRITE_DATA
|
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);
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
));
1140 static bool deltest20(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
1144 bool correct
= true;
1147 del_clean_area(cli1
, cli2
);
1149 /* Test 20 -- non-empty directory hardest to get right... */
1151 if (torture_setting_bool(tctx
, "samba3", false)) {
1155 smbcli_deltree(cli1
->tree
, dname
);
1157 dnum1
= smbcli_nt_create_full(cli1
->tree
, dname
, 0,
1159 SEC_FILE_WRITE_DATA
|
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);
1175 asprintf(&fullname
, "\\%s%s", dname
, fname
);
1176 fnum1
= smbcli_open(cli1
->tree
, fullname
, O_CREAT
|O_RDWR
,
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 !");
1195 asprintf(&fullname
, "\\%s%s", dname
, fname
);
1196 fnum1
= smbcli_open(cli1
->tree
, fullname
, O_CREAT
|O_RDWR
,
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
);
1214 static bool deltest20a(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
1218 bool correct
= true;
1220 del_clean_area(cli1
, cli2
);
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
,
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
)));
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
)
1284 bool correct
= true;
1286 del_clean_area(cli1
, cli2
);
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
,
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
,
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
;
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
)));
1383 static bool deltest21(struct torture_context
*tctx
)
1386 struct smbcli_state
*cli1
;
1387 struct smbcli_state
*cli2
;
1388 bool correct
= true;
1390 if (!torture_open_connection(&cli1
, tctx
, 0))
1393 if (!torture_open_connection(&cli2
, tctx
, 1))
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
);
1421 if (!torture_open_connection(&cli1
, tctx
, 0)) {
1425 /* On slow build farm machines it might happen that they are not fast
1426 * enogh to delete the file for this test */
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
,
1439 CHECK_STATUS(cli1
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
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
)
1454 struct smbcli_state
*cli1
;
1455 bool correct
= true;
1457 if (!torture_open_connection(&cli1
, tctx
, 0))
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,
1469 SEC_FILE_WRITE_DATA
|
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,
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,
1505 SEC_FILE_WRITE_DATA
|
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",
1518 CHECK_STATUS(cli1
, NT_STATUS_DELETE_PENDING
);
1520 smbcli_close(cli1
->tree
, dnum2
);
1521 CHECK_STATUS(cli1
, NT_STATUS_OK
);
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
)
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,
1542 SEC_FILE_WRITE_DATA
|
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,
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,
1564 SEC_FILE_WRITE_DATA
|
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");
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
);