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
, "close - 2 failed (%s)",
367 smbcli_errstr(cli1
->tree
)));
373 static bool deltest7(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
378 del_clean_area(cli1
, cli2
);
380 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
382 SEC_FILE_WRITE_DATA
|
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
)));
418 static bool deltest8(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
424 del_clean_area(cli1
, cli2
);
426 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
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,
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
));
475 static bool deltest9(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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!",
497 static bool deltest10(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
501 del_clean_area(cli1
, cli2
);
503 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
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 !",
529 static bool deltest11(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
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
)));
560 static bool deltest12(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
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 "
586 smbcli_errstr(cli1
->tree
)));
592 static bool deltest13(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
598 del_clean_area(cli1
, cli2
);
600 /* Test 13: Does resetting the delete on close flag affect a second
603 fnum1
= smbcli_nt_create_full(cli1
->tree
, fname
, 0,
607 FILE_ATTRIBUTE_NORMAL
,
608 NTCREATEX_SHARE_ACCESS_READ
|
609 NTCREATEX_SHARE_ACCESS_WRITE
|
610 NTCREATEX_SHARE_ACCESS_DELETE
,
611 NTCREATEX_DISP_OVERWRITE_IF
,
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,
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
,
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
,
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!",
660 smbcli_close(cli1
->tree
, fnum1
);
666 static bool deltest14(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
671 del_clean_area(cli1
, cli2
);
673 /* Test 14 -- directory */
675 dnum1
= smbcli_nt_create_full(cli1
->tree
, dname
, 0,
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,
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 !");
710 static bool deltest15(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
727 FILE_ATTRIBUTE_NORMAL
,
728 NTCREATEX_SHARE_ACCESS_READ
|
729 NTCREATEX_SHARE_ACCESS_WRITE
|
730 NTCREATEX_SHARE_ACCESS_DELETE
,
731 NTCREATEX_DISP_OVERWRITE_IF
,
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,
743 FILE_ATTRIBUTE_NORMAL
,
744 NTCREATEX_SHARE_ACCESS_READ
|
745 NTCREATEX_SHARE_ACCESS_WRITE
|
746 NTCREATEX_SHARE_ACCESS_DELETE
,
747 NTCREATEX_DISP_OVERWRITE_IF
,
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
764 correct
&= check_delete_on_close(tctx
, cli1
, fnum1
, fname_new
, true, __location__
);
766 fnum2
= smbcli_nt_create_full(cli2
->tree
, fname
, 0,
768 FILE_ATTRIBUTE_NORMAL
,
769 NTCREATEX_SHARE_ACCESS_READ
|
770 NTCREATEX_SHARE_ACCESS_WRITE
|
771 NTCREATEX_SHARE_ACCESS_DELETE
,
772 NTCREATEX_DISP_OVERWRITE_IF
,
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,
785 FILE_ATTRIBUTE_NORMAL
,
786 NTCREATEX_SHARE_ACCESS_READ
|
787 NTCREATEX_SHARE_ACCESS_WRITE
|
788 NTCREATEX_SHARE_ACCESS_DELETE
,
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,
799 FILE_ATTRIBUTE_NORMAL
,
800 NTCREATEX_SHARE_ACCESS_READ
|
801 NTCREATEX_SHARE_ACCESS_WRITE
|
802 NTCREATEX_SHARE_ACCESS_DELETE
,
806 torture_assert(tctx
, fnum1
== -1,
807 "smbcli_open succeeded, should have "
814 static bool deltest16(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
820 del_clean_area(cli1
, cli2
);
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,
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
,
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)",
884 static bool deltest17(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
890 del_clean_area(cli1
, cli2
);
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,
903 FILE_ATTRIBUTE_NORMAL
,
904 NTCREATEX_SHARE_ACCESS_READ
|
905 NTCREATEX_SHARE_ACCESS_WRITE
|
906 NTCREATEX_SHARE_ACCESS_DELETE
,
907 NTCREATEX_DISP_CREATE
,
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,
918 FILE_ATTRIBUTE_NORMAL
,
919 NTCREATEX_SHARE_ACCESS_READ
|
920 NTCREATEX_SHARE_ACCESS_WRITE
|
921 NTCREATEX_SHARE_ACCESS_DELETE
,
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
|
935 FILE_ATTRIBUTE_NORMAL
,
936 NTCREATEX_SHARE_ACCESS_READ
|
937 NTCREATEX_SHARE_ACCESS_WRITE
|
938 NTCREATEX_SHARE_ACCESS_DELETE
,
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
);
968 static bool deltest18(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
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,
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);
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)",
1047 static bool deltest19(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
1051 bool correct
= true;
1053 del_clean_area(cli1
, cli2
);
1057 smbcli_deltree(cli1
->tree
, dname
);
1059 /* Firstly open and create with all access */
1060 fnum1
= smbcli_nt_create_full(cli1
->tree
, dname
, 0,
1062 SEC_FILE_WRITE_DATA
|
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,
1080 SEC_FILE_WRITE_DATA
|
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);
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
));
1139 static bool deltest20(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
1143 bool correct
= true;
1146 del_clean_area(cli1
, cli2
);
1148 /* Test 20 -- non-empty directory hardest to get right... */
1150 if (torture_setting_bool(tctx
, "samba3", false)) {
1154 smbcli_deltree(cli1
->tree
, dname
);
1156 dnum1
= smbcli_nt_create_full(cli1
->tree
, dname
, 0,
1158 SEC_FILE_WRITE_DATA
|
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);
1174 asprintf(&fullname
, "\\%s%s", dname
, fname
);
1175 fnum1
= smbcli_open(cli1
->tree
, fullname
, O_CREAT
|O_RDWR
,
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 !");
1194 asprintf(&fullname
, "\\%s%s", dname
, fname
);
1195 fnum1
= smbcli_open(cli1
->tree
, fullname
, O_CREAT
|O_RDWR
,
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
);
1213 static bool deltest20a(struct torture_context
*tctx
, struct smbcli_state
*cli1
, struct smbcli_state
*cli2
)
1217 bool correct
= true;
1219 del_clean_area(cli1
, cli2
);
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
,
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
)));
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
)
1283 bool correct
= true;
1285 del_clean_area(cli1
, cli2
);
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
,
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
,
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
;
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
)));
1382 static bool deltest21(struct torture_context
*tctx
)
1385 struct smbcli_state
*cli1
;
1386 struct smbcli_state
*cli2
;
1387 bool correct
= true;
1389 if (!torture_open_connection(&cli1
, tctx
, 0))
1392 if (!torture_open_connection(&cli2
, tctx
, 1))
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
);
1420 if (!torture_open_connection(&cli1
, tctx
, 0)) {
1424 /* On slow build farm machines it might happen that they are not fast
1425 * enogh to delete the file for this test */
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
,
1438 CHECK_STATUS(cli1
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
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
)
1453 struct smbcli_state
*cli1
;
1454 bool correct
= true;
1456 if (!torture_open_connection(&cli1
, tctx
, 0))
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,
1468 SEC_FILE_WRITE_DATA
|
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,
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,
1504 SEC_FILE_WRITE_DATA
|
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",
1517 CHECK_STATUS(cli1
, NT_STATUS_DELETE_PENDING
);
1519 smbcli_close(cli1
->tree
, dnum2
);
1520 CHECK_STATUS(cli1
, NT_STATUS_OK
);
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
)
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,
1541 SEC_FILE_WRITE_DATA
|
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,
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,
1563 SEC_FILE_WRITE_DATA
|
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");
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
);