2 Unix SMB/CIFS implementation.
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/>.
21 #include "torture/torture.h"
22 #include "system/filesys.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
27 #define CHECK_STATUS(status, correct) do { \
28 if (!NT_STATUS_EQUAL(status, correct)) { \
29 printf("(%s) Incorrect status %s - should be %s\n", \
30 __location__, nt_errstr(status), nt_errstr(correct)); \
35 #define BASEDIR "\\testunlink"
40 static BOOL test_unlink(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
45 const char *fname = BASEDIR "\\test.txt";
47 if (!torture_setup_dir(cli, BASEDIR)) {
51 printf("Trying non-existant file\n");
52 io.unlink.in.pattern = fname;
53 io.unlink.in.attrib = 0;
54 status = smb_raw_unlink(cli->tree, &io);
55 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
57 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
59 io.unlink.in.pattern = fname;
60 io.unlink.in.attrib = 0;
61 status = smb_raw_unlink(cli->tree, &io);
62 CHECK_STATUS(status, NT_STATUS_OK);
64 printf("Trying a hidden file\n");
65 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
66 torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
68 io.unlink.in.pattern = fname;
69 io.unlink.in.attrib = 0;
70 status = smb_raw_unlink(cli->tree, &io);
71 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
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_OK);
78 io.unlink.in.pattern = fname;
79 io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
80 status = smb_raw_unlink(cli->tree, &io);
81 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
83 printf("Trying a directory\n");
84 io.unlink.in.pattern = BASEDIR;
85 io.unlink.in.attrib = 0;
86 status = smb_raw_unlink(cli->tree, &io);
87 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
89 io.unlink.in.pattern = BASEDIR;
90 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
91 status = smb_raw_unlink(cli->tree, &io);
92 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
94 printf("Trying a bad path\n");
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 = "\\..";
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_OBJECT_PATH_SYNTAX_BAD);
110 io.unlink.in.pattern = BASEDIR "\\..";
111 io.unlink.in.attrib = 0;
112 status = smb_raw_unlink(cli->tree, &io);
113 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
115 printf("Trying wildcards\n");
116 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
117 io.unlink.in.pattern = BASEDIR "\\t*.t";
118 io.unlink.in.attrib = 0;
119 status = smb_raw_unlink(cli->tree, &io);
120 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
122 io.unlink.in.pattern = BASEDIR "\\z*";
123 io.unlink.in.attrib = 0;
124 status = smb_raw_unlink(cli->tree, &io);
125 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
127 io.unlink.in.pattern = BASEDIR "\\z*";
128 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
129 status = smb_raw_unlink(cli->tree, &io);
131 if (lp_parm_bool(-1, "torture", "samba3", False)) {
133 * In Samba3 we gave up upon getting the error codes in
134 * wildcard unlink correct. Trying gentest showed that this is
135 * irregular beyond our capabilities. So for
136 * FILE_ATTRIBUTE_DIRECTORY we always return NAME_INVALID.
137 * Tried by jra and vl. If others feel like solving this
138 * puzzle, please tell us :-)
140 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
143 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
146 io.unlink.in.pattern = BASEDIR "\\*";
147 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
148 status = smb_raw_unlink(cli->tree, &io);
149 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
151 io.unlink.in.pattern = BASEDIR "\\?";
152 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
153 status = smb_raw_unlink(cli->tree, &io);
154 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
156 io.unlink.in.pattern = BASEDIR "\\t*";
157 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
158 status = smb_raw_unlink(cli->tree, &io);
159 if (lp_parm_bool(-1, "torture", "samba3", False)) {
160 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
163 CHECK_STATUS(status, NT_STATUS_OK);
166 smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
168 io.unlink.in.pattern = BASEDIR "\\*.dat";
169 io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
170 status = smb_raw_unlink(cli->tree, &io);
171 if (lp_parm_bool(-1, "torture", "samba3", False)) {
172 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
175 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
178 io.unlink.in.pattern = BASEDIR "\\*.tx?";
179 io.unlink.in.attrib = 0;
180 status = smb_raw_unlink(cli->tree, &io);
181 if (lp_parm_bool(-1, "torture", "samba3", False)) {
182 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
185 CHECK_STATUS(status, NT_STATUS_OK);
188 status = smb_raw_unlink(cli->tree, &io);
189 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
193 smb_raw_exit(cli->session);
194 smbcli_deltree(cli->tree, BASEDIR);
202 static BOOL test_delete_on_close(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
206 struct smb_rmdir dio;
210 const char *fname = BASEDIR "\\test.txt";
211 const char *dname = BASEDIR "\\test.dir";
212 const char *inside = BASEDIR "\\test.dir\\test.txt";
213 union smb_setfileinfo sfinfo;
215 if (!torture_setup_dir(cli, BASEDIR)) {
221 io.unlink.in.pattern = fname;
222 io.unlink.in.attrib = 0;
223 status = smb_raw_unlink(cli->tree, &io);
224 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
226 printf("Testing with delete_on_close 0\n");
227 fnum = create_complex_file(cli, mem_ctx, fname);
229 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
230 sfinfo.disposition_info.in.file.fnum = fnum;
231 sfinfo.disposition_info.in.delete_on_close = 0;
232 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
233 CHECK_STATUS(status, NT_STATUS_OK);
235 smbcli_close(cli->tree, fnum);
237 status = smb_raw_unlink(cli->tree, &io);
238 CHECK_STATUS(status, NT_STATUS_OK);
240 printf("Testing with delete_on_close 1\n");
241 fnum = create_complex_file(cli, mem_ctx, fname);
242 sfinfo.disposition_info.in.file.fnum = fnum;
243 sfinfo.disposition_info.in.delete_on_close = 1;
244 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
245 CHECK_STATUS(status, NT_STATUS_OK);
247 smbcli_close(cli->tree, fnum);
249 status = smb_raw_unlink(cli->tree, &io);
250 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
253 printf("Testing with directory and delete_on_close 0\n");
254 status = create_directory_handle(cli->tree, dname, &fnum);
255 CHECK_STATUS(status, NT_STATUS_OK);
257 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
258 sfinfo.disposition_info.in.file.fnum = fnum;
259 sfinfo.disposition_info.in.delete_on_close = 0;
260 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
261 CHECK_STATUS(status, NT_STATUS_OK);
263 smbcli_close(cli->tree, fnum);
265 status = smb_raw_rmdir(cli->tree, &dio);
266 CHECK_STATUS(status, NT_STATUS_OK);
268 printf("Testing with directory delete_on_close 1\n");
269 status = create_directory_handle(cli->tree, dname, &fnum);
270 CHECK_STATUS(status, NT_STATUS_OK);
272 sfinfo.disposition_info.in.file.fnum = fnum;
273 sfinfo.disposition_info.in.delete_on_close = 1;
274 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
275 CHECK_STATUS(status, NT_STATUS_OK);
277 smbcli_close(cli->tree, fnum);
279 status = smb_raw_rmdir(cli->tree, &dio);
280 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
283 if (!lp_parm_bool(-1, "torture", "samba3", False)) {
286 * Known deficiency, also skipped in base-delete.
289 printf("Testing with non-empty directory delete_on_close\n");
290 status = create_directory_handle(cli->tree, dname, &fnum);
291 CHECK_STATUS(status, NT_STATUS_OK);
293 fnum2 = create_complex_file(cli, mem_ctx, inside);
295 sfinfo.disposition_info.in.file.fnum = fnum;
296 sfinfo.disposition_info.in.delete_on_close = 1;
297 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
298 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
300 sfinfo.disposition_info.in.file.fnum = fnum2;
301 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
302 CHECK_STATUS(status, NT_STATUS_OK);
304 sfinfo.disposition_info.in.file.fnum = fnum;
305 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
306 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
308 smbcli_close(cli->tree, fnum2);
310 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
311 CHECK_STATUS(status, NT_STATUS_OK);
313 smbcli_close(cli->tree, fnum);
315 status = smb_raw_rmdir(cli->tree, &dio);
316 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
319 printf("Testing open dir with delete_on_close\n");
320 status = create_directory_handle(cli->tree, dname, &fnum);
321 CHECK_STATUS(status, NT_STATUS_OK);
323 smbcli_close(cli->tree, fnum);
324 fnum2 = create_complex_file(cli, mem_ctx, inside);
325 smbcli_close(cli->tree, fnum2);
327 op.generic.level = RAW_OPEN_NTCREATEX;
328 op.ntcreatex.in.root_fid = 0;
329 op.ntcreatex.in.flags = 0;
330 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
331 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
332 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
333 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
334 op.ntcreatex.in.alloc_size = 0;
335 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
336 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
337 op.ntcreatex.in.security_flags = 0;
338 op.ntcreatex.in.fname = dname;
340 status = smb_raw_open(cli->tree, mem_ctx, &op);
341 CHECK_STATUS(status, NT_STATUS_OK);
342 fnum = op.ntcreatex.out.file.fnum;
344 smbcli_close(cli->tree, fnum);
346 status = smb_raw_rmdir(cli->tree, &dio);
347 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
349 smbcli_deltree(cli->tree, dname);
351 printf("Testing double open dir with second delete_on_close\n");
352 status = create_directory_handle(cli->tree, dname, &fnum);
353 CHECK_STATUS(status, NT_STATUS_OK);
354 smbcli_close(cli->tree, fnum);
356 fnum2 = create_complex_file(cli, mem_ctx, inside);
357 smbcli_close(cli->tree, fnum2);
359 op.generic.level = RAW_OPEN_NTCREATEX;
360 op.ntcreatex.in.root_fid = 0;
361 op.ntcreatex.in.flags = 0;
362 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
363 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
364 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
365 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
366 op.ntcreatex.in.alloc_size = 0;
367 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
368 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
369 op.ntcreatex.in.security_flags = 0;
370 op.ntcreatex.in.fname = dname;
372 status = smb_raw_open(cli->tree, mem_ctx, &op);
373 CHECK_STATUS(status, NT_STATUS_OK);
374 fnum2 = op.ntcreatex.out.file.fnum;
376 smbcli_close(cli->tree, fnum2);
378 status = smb_raw_rmdir(cli->tree, &dio);
379 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
381 smbcli_deltree(cli->tree, dname);
383 printf("Testing pre-existing open dir with second delete_on_close\n");
384 status = create_directory_handle(cli->tree, dname, &fnum);
385 CHECK_STATUS(status, NT_STATUS_OK);
387 smbcli_close(cli->tree, fnum);
389 fnum = create_complex_file(cli, mem_ctx, inside);
390 smbcli_close(cli->tree, fnum);
392 /* we have a dir with a file in it, no handles open */
394 op.generic.level = RAW_OPEN_NTCREATEX;
395 op.ntcreatex.in.root_fid = 0;
396 op.ntcreatex.in.flags = 0;
397 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
398 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
399 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
400 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
401 op.ntcreatex.in.alloc_size = 0;
402 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
403 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
404 op.ntcreatex.in.security_flags = 0;
405 op.ntcreatex.in.fname = dname;
407 status = smb_raw_open(cli->tree, mem_ctx, &op);
408 CHECK_STATUS(status, NT_STATUS_OK);
409 fnum = op.ntcreatex.out.file.fnum;
411 /* open without delete on close */
412 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
413 status = smb_raw_open(cli->tree, mem_ctx, &op);
414 CHECK_STATUS(status, NT_STATUS_OK);
415 fnum2 = op.ntcreatex.out.file.fnum;
417 /* close 2nd file handle */
418 smbcli_close(cli->tree, fnum2);
420 status = smb_raw_rmdir(cli->tree, &dio);
421 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
424 smbcli_close(cli->tree, fnum);
426 status = smb_raw_rmdir(cli->tree, &dio);
427 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
430 smb_raw_exit(cli->session);
431 smbcli_deltree(cli->tree, BASEDIR);
437 basic testing of unlink calls
439 BOOL torture_raw_unlink(struct torture_context *torture)
441 struct smbcli_state *cli;
445 if (!torture_open_connection(&cli, 0)) {
449 mem_ctx = talloc_init("torture_raw_unlink");
451 ret &= test_unlink(cli, mem_ctx);
452 ret &= test_delete_on_close(cli, mem_ctx);
454 torture_close_connection(cli);
455 talloc_free(mem_ctx);