ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / torture / raw / unlink.c
blob77cbb4acb612d4511f0aabd7e31b2b3ccec23fcc
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"
27 #include "torture/raw/proto.h"
29 #define CHECK_STATUS(status, correct) \
30 torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, __location__)
32 #define BASEDIR "\\testunlink"
35 test unlink ops
37 static bool test_unlink(struct torture_context *tctx, struct smbcli_state *cli)
39 union smb_unlink io;
40 NTSTATUS status;
41 bool ret = true;
42 const char *fname = BASEDIR "\\test.txt";
44 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
46 printf("Trying non-existent file\n");
47 io.unlink.in.pattern = fname;
48 io.unlink.in.attrib = 0;
49 status = smb_raw_unlink(cli->tree, &io);
50 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
52 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
54 io.unlink.in.pattern = fname;
55 io.unlink.in.attrib = 0;
56 status = smb_raw_unlink(cli->tree, &io);
57 CHECK_STATUS(status, NT_STATUS_OK);
59 printf("Trying a hidden file\n");
60 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
61 torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
63 io.unlink.in.pattern = fname;
64 io.unlink.in.attrib = 0;
65 status = smb_raw_unlink(cli->tree, &io);
66 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
68 io.unlink.in.pattern = fname;
69 io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
70 status = smb_raw_unlink(cli->tree, &io);
71 CHECK_STATUS(status, NT_STATUS_OK);
73 io.unlink.in.pattern = fname;
74 io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
75 status = smb_raw_unlink(cli->tree, &io);
76 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
78 printf("Trying a directory\n");
79 io.unlink.in.pattern = BASEDIR;
80 io.unlink.in.attrib = 0;
81 status = smb_raw_unlink(cli->tree, &io);
82 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
84 io.unlink.in.pattern = BASEDIR;
85 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
86 status = smb_raw_unlink(cli->tree, &io);
87 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
89 printf("Trying a bad path\n");
90 io.unlink.in.pattern = "..";
91 io.unlink.in.attrib = 0;
92 status = smb_raw_unlink(cli->tree, &io);
93 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
95 io.unlink.in.pattern = "\\..";
96 io.unlink.in.attrib = 0;
97 status = smb_raw_unlink(cli->tree, &io);
98 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
100 io.unlink.in.pattern = BASEDIR "\\..\\..";
101 io.unlink.in.attrib = 0;
102 status = smb_raw_unlink(cli->tree, &io);
103 CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
105 io.unlink.in.pattern = BASEDIR "\\..";
106 io.unlink.in.attrib = 0;
107 status = smb_raw_unlink(cli->tree, &io);
108 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
110 done:
111 smb_raw_exit(cli->session);
112 smbcli_deltree(cli->tree, BASEDIR);
113 return ret;
118 test delete on close
120 static bool test_delete_on_close(struct torture_context *tctx,
121 struct smbcli_state *cli)
123 union smb_open op;
124 union smb_unlink io;
125 struct smb_rmdir dio;
126 NTSTATUS status;
127 bool ret = true;
128 int fnum, fnum2;
129 const char *fname = BASEDIR "\\test.txt";
130 const char *dname = BASEDIR "\\test.dir";
131 const char *inside = BASEDIR "\\test.dir\\test.txt";
132 union smb_setfileinfo sfinfo;
134 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
136 dio.in.path = dname;
138 io.unlink.in.pattern = fname;
139 io.unlink.in.attrib = 0;
140 status = smb_raw_unlink(cli->tree, &io);
141 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
143 printf("Testing with delete_on_close 0\n");
144 fnum = create_complex_file(cli, tctx, fname);
146 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
147 sfinfo.disposition_info.in.file.fnum = fnum;
148 sfinfo.disposition_info.in.delete_on_close = 0;
149 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
150 CHECK_STATUS(status, NT_STATUS_OK);
152 smbcli_close(cli->tree, fnum);
154 status = smb_raw_unlink(cli->tree, &io);
155 CHECK_STATUS(status, NT_STATUS_OK);
157 printf("Testing with delete_on_close 1\n");
158 fnum = create_complex_file(cli, tctx, fname);
159 sfinfo.disposition_info.in.file.fnum = fnum;
160 sfinfo.disposition_info.in.delete_on_close = 1;
161 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
162 CHECK_STATUS(status, NT_STATUS_OK);
164 smbcli_close(cli->tree, fnum);
166 status = smb_raw_unlink(cli->tree, &io);
167 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
170 printf("Testing with directory and delete_on_close 0\n");
171 status = create_directory_handle(cli->tree, dname, &fnum);
172 CHECK_STATUS(status, NT_STATUS_OK);
174 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
175 sfinfo.disposition_info.in.file.fnum = fnum;
176 sfinfo.disposition_info.in.delete_on_close = 0;
177 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
178 CHECK_STATUS(status, NT_STATUS_OK);
180 smbcli_close(cli->tree, fnum);
182 status = smb_raw_rmdir(cli->tree, &dio);
183 CHECK_STATUS(status, NT_STATUS_OK);
185 printf("Testing with directory delete_on_close 1\n");
186 status = create_directory_handle(cli->tree, dname, &fnum);
187 CHECK_STATUS(status, NT_STATUS_OK);
189 sfinfo.disposition_info.in.file.fnum = fnum;
190 sfinfo.disposition_info.in.delete_on_close = 1;
191 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
192 CHECK_STATUS(status, NT_STATUS_OK);
194 smbcli_close(cli->tree, fnum);
196 status = smb_raw_rmdir(cli->tree, &dio);
197 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
200 if (!torture_setting_bool(tctx, "samba3", false)) {
203 * Known deficiency, also skipped in base-delete.
206 printf("Testing with non-empty directory delete_on_close\n");
207 status = create_directory_handle(cli->tree, dname, &fnum);
208 CHECK_STATUS(status, NT_STATUS_OK);
210 fnum2 = create_complex_file(cli, tctx, inside);
212 sfinfo.disposition_info.in.file.fnum = fnum;
213 sfinfo.disposition_info.in.delete_on_close = 1;
214 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
215 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
217 sfinfo.disposition_info.in.file.fnum = fnum2;
218 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
219 CHECK_STATUS(status, NT_STATUS_OK);
221 sfinfo.disposition_info.in.file.fnum = fnum;
222 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
223 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
225 smbcli_close(cli->tree, fnum2);
227 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
228 CHECK_STATUS(status, NT_STATUS_OK);
230 smbcli_close(cli->tree, fnum);
232 status = smb_raw_rmdir(cli->tree, &dio);
233 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
236 printf("Testing open dir with delete_on_close\n");
237 status = create_directory_handle(cli->tree, dname, &fnum);
238 CHECK_STATUS(status, NT_STATUS_OK);
240 smbcli_close(cli->tree, fnum);
241 fnum2 = create_complex_file(cli, tctx, inside);
242 smbcli_close(cli->tree, fnum2);
244 op.generic.level = RAW_OPEN_NTCREATEX;
245 op.ntcreatex.in.root_fid.fnum = 0;
246 op.ntcreatex.in.flags = 0;
247 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
248 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
249 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
250 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
251 op.ntcreatex.in.alloc_size = 0;
252 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
253 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
254 op.ntcreatex.in.security_flags = 0;
255 op.ntcreatex.in.fname = dname;
257 status = smb_raw_open(cli->tree, tctx, &op);
258 CHECK_STATUS(status, NT_STATUS_OK);
259 fnum = op.ntcreatex.out.file.fnum;
261 smbcli_close(cli->tree, fnum);
263 status = smb_raw_rmdir(cli->tree, &dio);
264 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
266 smbcli_deltree(cli->tree, dname);
268 printf("Testing double open dir with second delete_on_close\n");
269 status = create_directory_handle(cli->tree, dname, &fnum);
270 CHECK_STATUS(status, NT_STATUS_OK);
271 smbcli_close(cli->tree, fnum);
273 fnum2 = create_complex_file(cli, tctx, inside);
274 smbcli_close(cli->tree, fnum2);
276 op.generic.level = RAW_OPEN_NTCREATEX;
277 op.ntcreatex.in.root_fid.fnum = 0;
278 op.ntcreatex.in.flags = 0;
279 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
280 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
281 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
282 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
283 op.ntcreatex.in.alloc_size = 0;
284 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
285 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
286 op.ntcreatex.in.security_flags = 0;
287 op.ntcreatex.in.fname = dname;
289 status = smb_raw_open(cli->tree, tctx, &op);
290 CHECK_STATUS(status, NT_STATUS_OK);
291 fnum2 = op.ntcreatex.out.file.fnum;
293 smbcli_close(cli->tree, fnum2);
295 status = smb_raw_rmdir(cli->tree, &dio);
296 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
298 smbcli_deltree(cli->tree, dname);
300 printf("Testing pre-existing open dir with second delete_on_close\n");
301 status = create_directory_handle(cli->tree, dname, &fnum);
302 CHECK_STATUS(status, NT_STATUS_OK);
304 smbcli_close(cli->tree, fnum);
306 fnum = create_complex_file(cli, tctx, inside);
307 smbcli_close(cli->tree, fnum);
309 /* we have a dir with a file in it, no handles open */
311 op.generic.level = RAW_OPEN_NTCREATEX;
312 op.ntcreatex.in.root_fid.fnum = 0;
313 op.ntcreatex.in.flags = 0;
314 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
315 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
316 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
317 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
318 op.ntcreatex.in.alloc_size = 0;
319 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
320 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
321 op.ntcreatex.in.security_flags = 0;
322 op.ntcreatex.in.fname = dname;
324 status = smb_raw_open(cli->tree, tctx, &op);
325 CHECK_STATUS(status, NT_STATUS_OK);
326 fnum = op.ntcreatex.out.file.fnum;
328 /* open without delete on close */
329 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
330 status = smb_raw_open(cli->tree, tctx, &op);
331 CHECK_STATUS(status, NT_STATUS_OK);
332 fnum2 = op.ntcreatex.out.file.fnum;
334 /* close 2nd file handle */
335 smbcli_close(cli->tree, fnum2);
337 status = smb_raw_rmdir(cli->tree, &dio);
338 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
341 smbcli_close(cli->tree, fnum);
343 status = smb_raw_rmdir(cli->tree, &dio);
344 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
346 done:
347 smb_raw_exit(cli->session);
348 smbcli_deltree(cli->tree, BASEDIR);
349 return ret;
353 struct unlink_defer_cli_state {
354 struct torture_context *tctx;
355 struct smbcli_state *cli1;
359 * A handler function for oplock break requests. Ack it as a break to none
361 static bool oplock_handler_ack_to_none(struct smbcli_transport *transport,
362 uint16_t tid, uint16_t fnum,
363 uint8_t level, void *private_data)
365 struct unlink_defer_cli_state *ud_cli_state =
366 (struct unlink_defer_cli_state *)private_data;
367 union smb_setfileinfo sfinfo;
368 bool ret;
369 struct smbcli_request *req = NULL;
371 torture_comment(ud_cli_state->tctx, "delete the file before sending "
372 "the ack.");
374 /* cli1: set delete on close */
375 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
376 sfinfo.disposition_info.in.file.fnum = fnum;
377 sfinfo.disposition_info.in.delete_on_close = 1;
378 req = smb_raw_setfileinfo_send(ud_cli_state->cli1->tree, &sfinfo);
379 if (!req) {
380 torture_comment(ud_cli_state->tctx, "smb_raw_setfileinfo_send "
381 "failed.");
384 smbcli_close(ud_cli_state->cli1->tree, fnum);
386 torture_comment(ud_cli_state->tctx, "Acking the oplock to NONE\n");
388 ret = smbcli_oplock_ack(ud_cli_state->cli1->tree, fnum,
389 OPLOCK_BREAK_TO_NONE);
391 return ret;
394 static bool test_unlink_defer(struct torture_context *tctx,
395 struct smbcli_state *cli1,
396 struct smbcli_state *cli2)
398 const char *fname = BASEDIR "\\test_unlink_defer.dat";
399 NTSTATUS status;
400 bool ret = true;
401 union smb_open io;
402 union smb_unlink unl;
403 struct unlink_defer_cli_state ud_cli_state = {};
405 if (!torture_setup_dir(cli1, BASEDIR)) {
406 return false;
409 /* cleanup */
410 smbcli_unlink(cli1->tree, fname);
412 ud_cli_state.tctx = tctx;
413 ud_cli_state.cli1 = cli1;
415 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none,
416 &ud_cli_state);
418 io.generic.level = RAW_OPEN_NTCREATEX;
419 io.ntcreatex.in.root_fid.fnum = 0;
420 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
421 io.ntcreatex.in.alloc_size = 0;
422 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
423 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
424 NTCREATEX_SHARE_ACCESS_WRITE |
425 NTCREATEX_SHARE_ACCESS_DELETE;
426 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
427 io.ntcreatex.in.create_options = 0;
428 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
429 io.ntcreatex.in.security_flags = 0;
430 io.ntcreatex.in.fname = fname;
432 /* cli1: open file with a batch oplock. */
433 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
434 NTCREATEX_FLAGS_REQUEST_OPLOCK |
435 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
437 status = smb_raw_open(cli1->tree, tctx, &io);
438 CHECK_STATUS(status, NT_STATUS_OK);
440 /* cli2: Try to unlink it, but block on the oplock */
441 torture_comment(tctx, "Try an unlink (should defer the open\n");
442 unl.unlink.in.pattern = fname;
443 unl.unlink.in.attrib = 0;
444 status = smb_raw_unlink(cli2->tree, &unl);
446 done:
447 smb_raw_exit(cli1->session);
448 smb_raw_exit(cli2->session);
449 smbcli_deltree(cli1->tree, BASEDIR);
450 return ret;
454 basic testing of unlink calls
456 struct torture_suite *torture_raw_unlink(TALLOC_CTX *mem_ctx)
458 struct torture_suite *suite = torture_suite_create(mem_ctx, "unlink");
460 torture_suite_add_1smb_test(suite, "unlink", test_unlink);
461 torture_suite_add_1smb_test(suite, "delete_on_close", test_delete_on_close);
462 torture_suite_add_2smb_test(suite, "unlink-defer", test_unlink_defer);
464 return suite;