Backport FSCTL codes from master
[Samba.git] / source4 / torture / raw / unlink.c
blobd1ad78508fcbf5a1d46dd48d0ad84606cf88f12f
1 /*
2 Unix SMB/CIFS implementation.
3 unlink test suite
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "torture/torture.h"
22 #include "system/filesys.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
28 #define CHECK_STATUS(status, correct) do { \
29 if (!NT_STATUS_EQUAL(status, correct)) { \
30 printf("(%s) Incorrect status %s - should be %s\n", \
31 __location__, nt_errstr(status), nt_errstr(correct)); \
32 ret = false; \
33 goto done; \
34 }} while (0)
36 #define BASEDIR "\\testunlink"
39 test unlink ops
41 static bool test_unlink(struct torture_context *tctx, struct smbcli_state *cli)
43 union smb_unlink io;
44 NTSTATUS status;
45 bool ret = true;
46 const char *fname = BASEDIR "\\test.txt";
48 if (!torture_setup_dir(cli, BASEDIR)) {
49 return false;
52 printf("Trying non-existant file\n");
53 io.unlink.in.pattern = fname;
54 io.unlink.in.attrib = 0;
55 status = smb_raw_unlink(cli->tree, &io);
56 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
58 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
60 io.unlink.in.pattern = fname;
61 io.unlink.in.attrib = 0;
62 status = smb_raw_unlink(cli->tree, &io);
63 CHECK_STATUS(status, NT_STATUS_OK);
65 printf("Trying a hidden file\n");
66 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
67 torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
69 io.unlink.in.pattern = fname;
70 io.unlink.in.attrib = 0;
71 status = smb_raw_unlink(cli->tree, &io);
72 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
74 io.unlink.in.pattern = fname;
75 io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
76 status = smb_raw_unlink(cli->tree, &io);
77 CHECK_STATUS(status, NT_STATUS_OK);
79 io.unlink.in.pattern = fname;
80 io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
81 status = smb_raw_unlink(cli->tree, &io);
82 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
84 printf("Trying a directory\n");
85 io.unlink.in.pattern = BASEDIR;
86 io.unlink.in.attrib = 0;
87 status = smb_raw_unlink(cli->tree, &io);
88 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
90 io.unlink.in.pattern = BASEDIR;
91 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
92 status = smb_raw_unlink(cli->tree, &io);
93 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
95 printf("Trying a bad path\n");
96 io.unlink.in.pattern = "..";
97 io.unlink.in.attrib = 0;
98 status = smb_raw_unlink(cli->tree, &io);
99 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
101 io.unlink.in.pattern = "\\..";
102 io.unlink.in.attrib = 0;
103 status = smb_raw_unlink(cli->tree, &io);
104 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
106 io.unlink.in.pattern = BASEDIR "\\..\\..";
107 io.unlink.in.attrib = 0;
108 status = smb_raw_unlink(cli->tree, &io);
109 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
111 io.unlink.in.pattern = BASEDIR "\\..";
112 io.unlink.in.attrib = 0;
113 status = smb_raw_unlink(cli->tree, &io);
114 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
116 printf("Trying wildcards\n");
117 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
118 io.unlink.in.pattern = BASEDIR "\\t*.t";
119 io.unlink.in.attrib = 0;
120 status = smb_raw_unlink(cli->tree, &io);
121 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
123 io.unlink.in.pattern = BASEDIR "\\z*";
124 io.unlink.in.attrib = 0;
125 status = smb_raw_unlink(cli->tree, &io);
126 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
128 io.unlink.in.pattern = BASEDIR "\\z*";
129 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
130 status = smb_raw_unlink(cli->tree, &io);
132 if (torture_setting_bool(tctx, "samba3", false)) {
134 * In Samba3 we gave up upon getting the error codes in
135 * wildcard unlink correct. Trying gentest showed that this is
136 * irregular beyond our capabilities. So for
137 * FILE_ATTRIBUTE_DIRECTORY we always return NAME_INVALID.
138 * Tried by jra and vl. If others feel like solving this
139 * puzzle, please tell us :-)
141 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
143 else {
144 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
147 io.unlink.in.pattern = BASEDIR "\\*";
148 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
149 status = smb_raw_unlink(cli->tree, &io);
150 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
152 io.unlink.in.pattern = BASEDIR "\\?";
153 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
154 status = smb_raw_unlink(cli->tree, &io);
155 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
157 io.unlink.in.pattern = BASEDIR "\\t*";
158 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
159 status = smb_raw_unlink(cli->tree, &io);
160 if (torture_setting_bool(tctx, "samba3", false)) {
161 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
163 else {
164 CHECK_STATUS(status, NT_STATUS_OK);
167 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
169 io.unlink.in.pattern = BASEDIR "\\*.dat";
170 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
171 status = smb_raw_unlink(cli->tree, &io);
172 if (torture_setting_bool(tctx, "samba3", false)) {
173 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
175 else {
176 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
179 io.unlink.in.pattern = BASEDIR "\\*.tx?";
180 io.unlink.in.attrib = 0;
181 status = smb_raw_unlink(cli->tree, &io);
182 if (torture_setting_bool(tctx, "samba3", false)) {
183 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
185 else {
186 CHECK_STATUS(status, NT_STATUS_OK);
189 status = smb_raw_unlink(cli->tree, &io);
190 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
193 done:
194 smb_raw_exit(cli->session);
195 smbcli_deltree(cli->tree, BASEDIR);
196 return ret;
201 test delete on close
203 static bool test_delete_on_close(struct torture_context *tctx,
204 struct smbcli_state *cli)
206 union smb_open op;
207 union smb_unlink io;
208 struct smb_rmdir dio;
209 NTSTATUS status;
210 bool ret = true;
211 int fnum, fnum2;
212 const char *fname = BASEDIR "\\test.txt";
213 const char *dname = BASEDIR "\\test.dir";
214 const char *inside = BASEDIR "\\test.dir\\test.txt";
215 union smb_setfileinfo sfinfo;
217 if (!torture_setup_dir(cli, BASEDIR)) {
218 return false;
221 dio.in.path = dname;
223 io.unlink.in.pattern = fname;
224 io.unlink.in.attrib = 0;
225 status = smb_raw_unlink(cli->tree, &io);
226 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
228 printf("Testing with delete_on_close 0\n");
229 fnum = create_complex_file(cli, tctx, fname);
231 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
232 sfinfo.disposition_info.in.file.fnum = fnum;
233 sfinfo.disposition_info.in.delete_on_close = 0;
234 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
235 CHECK_STATUS(status, NT_STATUS_OK);
237 smbcli_close(cli->tree, fnum);
239 status = smb_raw_unlink(cli->tree, &io);
240 CHECK_STATUS(status, NT_STATUS_OK);
242 printf("Testing with delete_on_close 1\n");
243 fnum = create_complex_file(cli, tctx, fname);
244 sfinfo.disposition_info.in.file.fnum = fnum;
245 sfinfo.disposition_info.in.delete_on_close = 1;
246 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
247 CHECK_STATUS(status, NT_STATUS_OK);
249 smbcli_close(cli->tree, fnum);
251 status = smb_raw_unlink(cli->tree, &io);
252 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
255 printf("Testing with directory and delete_on_close 0\n");
256 status = create_directory_handle(cli->tree, dname, &fnum);
257 CHECK_STATUS(status, NT_STATUS_OK);
259 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
260 sfinfo.disposition_info.in.file.fnum = fnum;
261 sfinfo.disposition_info.in.delete_on_close = 0;
262 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
263 CHECK_STATUS(status, NT_STATUS_OK);
265 smbcli_close(cli->tree, fnum);
267 status = smb_raw_rmdir(cli->tree, &dio);
268 CHECK_STATUS(status, NT_STATUS_OK);
270 printf("Testing with directory delete_on_close 1\n");
271 status = create_directory_handle(cli->tree, dname, &fnum);
272 CHECK_STATUS(status, NT_STATUS_OK);
274 sfinfo.disposition_info.in.file.fnum = fnum;
275 sfinfo.disposition_info.in.delete_on_close = 1;
276 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
277 CHECK_STATUS(status, NT_STATUS_OK);
279 smbcli_close(cli->tree, fnum);
281 status = smb_raw_rmdir(cli->tree, &dio);
282 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
285 if (!torture_setting_bool(tctx, "samba3", false)) {
288 * Known deficiency, also skipped in base-delete.
291 printf("Testing with non-empty directory delete_on_close\n");
292 status = create_directory_handle(cli->tree, dname, &fnum);
293 CHECK_STATUS(status, NT_STATUS_OK);
295 fnum2 = create_complex_file(cli, tctx, inside);
297 sfinfo.disposition_info.in.file.fnum = fnum;
298 sfinfo.disposition_info.in.delete_on_close = 1;
299 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
300 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
302 sfinfo.disposition_info.in.file.fnum = fnum2;
303 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
304 CHECK_STATUS(status, NT_STATUS_OK);
306 sfinfo.disposition_info.in.file.fnum = fnum;
307 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
308 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
310 smbcli_close(cli->tree, fnum2);
312 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
313 CHECK_STATUS(status, NT_STATUS_OK);
315 smbcli_close(cli->tree, fnum);
317 status = smb_raw_rmdir(cli->tree, &dio);
318 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
321 printf("Testing open dir with delete_on_close\n");
322 status = create_directory_handle(cli->tree, dname, &fnum);
323 CHECK_STATUS(status, NT_STATUS_OK);
325 smbcli_close(cli->tree, fnum);
326 fnum2 = create_complex_file(cli, tctx, inside);
327 smbcli_close(cli->tree, fnum2);
329 op.generic.level = RAW_OPEN_NTCREATEX;
330 op.ntcreatex.in.root_fid.fnum = 0;
331 op.ntcreatex.in.flags = 0;
332 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
333 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
334 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
335 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
336 op.ntcreatex.in.alloc_size = 0;
337 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
338 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
339 op.ntcreatex.in.security_flags = 0;
340 op.ntcreatex.in.fname = dname;
342 status = smb_raw_open(cli->tree, tctx, &op);
343 CHECK_STATUS(status, NT_STATUS_OK);
344 fnum = op.ntcreatex.out.file.fnum;
346 smbcli_close(cli->tree, fnum);
348 status = smb_raw_rmdir(cli->tree, &dio);
349 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
351 smbcli_deltree(cli->tree, dname);
353 printf("Testing double open dir with second delete_on_close\n");
354 status = create_directory_handle(cli->tree, dname, &fnum);
355 CHECK_STATUS(status, NT_STATUS_OK);
356 smbcli_close(cli->tree, fnum);
358 fnum2 = create_complex_file(cli, tctx, inside);
359 smbcli_close(cli->tree, fnum2);
361 op.generic.level = RAW_OPEN_NTCREATEX;
362 op.ntcreatex.in.root_fid.fnum = 0;
363 op.ntcreatex.in.flags = 0;
364 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
365 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
366 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
367 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
368 op.ntcreatex.in.alloc_size = 0;
369 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
370 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
371 op.ntcreatex.in.security_flags = 0;
372 op.ntcreatex.in.fname = dname;
374 status = smb_raw_open(cli->tree, tctx, &op);
375 CHECK_STATUS(status, NT_STATUS_OK);
376 fnum2 = op.ntcreatex.out.file.fnum;
378 smbcli_close(cli->tree, fnum2);
380 status = smb_raw_rmdir(cli->tree, &dio);
381 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
383 smbcli_deltree(cli->tree, dname);
385 printf("Testing pre-existing open dir with second delete_on_close\n");
386 status = create_directory_handle(cli->tree, dname, &fnum);
387 CHECK_STATUS(status, NT_STATUS_OK);
389 smbcli_close(cli->tree, fnum);
391 fnum = create_complex_file(cli, tctx, inside);
392 smbcli_close(cli->tree, fnum);
394 /* we have a dir with a file in it, no handles open */
396 op.generic.level = RAW_OPEN_NTCREATEX;
397 op.ntcreatex.in.root_fid.fnum = 0;
398 op.ntcreatex.in.flags = 0;
399 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
400 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
401 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
402 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
403 op.ntcreatex.in.alloc_size = 0;
404 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
405 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
406 op.ntcreatex.in.security_flags = 0;
407 op.ntcreatex.in.fname = dname;
409 status = smb_raw_open(cli->tree, tctx, &op);
410 CHECK_STATUS(status, NT_STATUS_OK);
411 fnum = op.ntcreatex.out.file.fnum;
413 /* open without delete on close */
414 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
415 status = smb_raw_open(cli->tree, tctx, &op);
416 CHECK_STATUS(status, NT_STATUS_OK);
417 fnum2 = op.ntcreatex.out.file.fnum;
419 /* close 2nd file handle */
420 smbcli_close(cli->tree, fnum2);
422 status = smb_raw_rmdir(cli->tree, &dio);
423 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
426 smbcli_close(cli->tree, fnum);
428 status = smb_raw_rmdir(cli->tree, &dio);
429 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
431 done:
432 smb_raw_exit(cli->session);
433 smbcli_deltree(cli->tree, BASEDIR);
434 return ret;
438 struct unlink_defer_cli_state {
439 struct torture_context *tctx;
440 struct smbcli_state *cli1;
444 * A handler function for oplock break requests. Ack it as a break to none
446 static bool oplock_handler_ack_to_none(struct smbcli_transport *transport,
447 uint16_t tid, uint16_t fnum,
448 uint8_t level, void *private_data)
450 struct unlink_defer_cli_state *ud_cli_state =
451 (struct unlink_defer_cli_state *)private_data;
452 union smb_setfileinfo sfinfo;
453 bool ret;
454 struct smbcli_request *req = NULL;
456 torture_comment(ud_cli_state->tctx, "delete the file before sending "
457 "the ack.");
459 /* cli1: set delete on close */
460 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
461 sfinfo.disposition_info.in.file.fnum = fnum;
462 sfinfo.disposition_info.in.delete_on_close = 1;
463 req = smb_raw_setfileinfo_send(ud_cli_state->cli1->tree, &sfinfo);
465 smbcli_close(ud_cli_state->cli1->tree, fnum);
467 torture_comment(ud_cli_state->tctx, "Acking the oplock to NONE\n");
469 ret = smbcli_oplock_ack(ud_cli_state->cli1->tree, fnum,
470 OPLOCK_BREAK_TO_NONE);
472 return ret;
475 static bool test_unlink_defer(struct torture_context *tctx,
476 struct smbcli_state *cli1,
477 struct smbcli_state *cli2)
479 const char *fname = BASEDIR "\\test_unlink_defer.dat";
480 NTSTATUS status;
481 bool ret = true;
482 union smb_open io;
483 union smb_unlink unl;
484 uint16_t fnum=0;
485 struct unlink_defer_cli_state ud_cli_state = {};
487 if (!torture_setup_dir(cli1, BASEDIR)) {
488 return false;
491 /* cleanup */
492 smbcli_unlink(cli1->tree, fname);
494 ud_cli_state.tctx = tctx;
495 ud_cli_state.cli1 = cli1;
497 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none,
498 &ud_cli_state);
500 io.generic.level = RAW_OPEN_NTCREATEX;
501 io.ntcreatex.in.root_fid.fnum = 0;
502 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
503 io.ntcreatex.in.alloc_size = 0;
504 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
505 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
506 NTCREATEX_SHARE_ACCESS_WRITE |
507 NTCREATEX_SHARE_ACCESS_DELETE;
508 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
509 io.ntcreatex.in.create_options = 0;
510 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
511 io.ntcreatex.in.security_flags = 0;
512 io.ntcreatex.in.fname = fname;
514 /* cli1: open file with a batch oplock. */
515 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
516 NTCREATEX_FLAGS_REQUEST_OPLOCK |
517 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
519 status = smb_raw_open(cli1->tree, tctx, &io);
520 CHECK_STATUS(status, NT_STATUS_OK);
521 fnum = io.ntcreatex.out.file.fnum;
523 /* cli2: Try to unlink it, but block on the oplock */
524 torture_comment(tctx, "Try an unlink (should defer the open\n");
525 unl.unlink.in.pattern = fname;
526 unl.unlink.in.attrib = 0;
527 status = smb_raw_unlink(cli2->tree, &unl);
529 done:
530 smb_raw_exit(cli1->session);
531 smb_raw_exit(cli2->session);
532 smbcli_deltree(cli1->tree, BASEDIR);
533 return ret;
537 basic testing of unlink calls
539 struct torture_suite *torture_raw_unlink(TALLOC_CTX *mem_ctx)
541 struct torture_suite *suite = torture_suite_create(mem_ctx, "unlink");
543 torture_suite_add_1smb_test(suite, "unlink", test_unlink);
544 torture_suite_add_1smb_test(suite, "delete_on_close", test_delete_on_close);
545 torture_suite_add_2smb_test(suite, "unlink-defer", test_unlink_defer);
547 return suite;