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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "torture/torture.h"
23 #include "system/filesys.h"
24 #include "libcli/raw/libcliraw.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)); \
36 #define BASEDIR "\\testunlink"
41 static BOOL test_unlink(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
46 const char *fname = BASEDIR "\\test.txt";
48 if (!torture_setup_dir(cli, BASEDIR)) {
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 (lp_parm_bool(-1, "torture", "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);
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 (lp_parm_bool(-1, "torture", "samba3", False)) {
161 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
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 (lp_parm_bool(-1, "torture", "samba3", False)) {
173 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
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 (lp_parm_bool(-1, "torture", "samba3", False)) {
183 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
186 CHECK_STATUS(status, NT_STATUS_OK);
189 status = smb_raw_unlink(cli->tree, &io);
190 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
194 smb_raw_exit(cli->session);
195 smbcli_deltree(cli->tree, BASEDIR);
203 static BOOL test_delete_on_close(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
207 struct smb_rmdir dio;
211 const char *fname = BASEDIR "\\test.txt";
212 const char *dname = BASEDIR "\\test.dir";
213 const char *inside = BASEDIR "\\test.dir\\test.txt";
214 union smb_setfileinfo sfinfo;
216 if (!torture_setup_dir(cli, BASEDIR)) {
222 io.unlink.in.pattern = fname;
223 io.unlink.in.attrib = 0;
224 status = smb_raw_unlink(cli->tree, &io);
225 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
227 printf("Testing with delete_on_close 0\n");
228 fnum = create_complex_file(cli, mem_ctx, fname);
230 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
231 sfinfo.disposition_info.in.file.fnum = fnum;
232 sfinfo.disposition_info.in.delete_on_close = 0;
233 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
234 CHECK_STATUS(status, NT_STATUS_OK);
236 smbcli_close(cli->tree, fnum);
238 status = smb_raw_unlink(cli->tree, &io);
239 CHECK_STATUS(status, NT_STATUS_OK);
241 printf("Testing with delete_on_close 1\n");
242 fnum = create_complex_file(cli, mem_ctx, fname);
243 sfinfo.disposition_info.in.file.fnum = fnum;
244 sfinfo.disposition_info.in.delete_on_close = 1;
245 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
246 CHECK_STATUS(status, NT_STATUS_OK);
248 smbcli_close(cli->tree, fnum);
250 status = smb_raw_unlink(cli->tree, &io);
251 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
254 printf("Testing with directory and delete_on_close 0\n");
255 status = create_directory_handle(cli->tree, dname, &fnum);
256 CHECK_STATUS(status, NT_STATUS_OK);
258 sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
259 sfinfo.disposition_info.in.file.fnum = fnum;
260 sfinfo.disposition_info.in.delete_on_close = 0;
261 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
262 CHECK_STATUS(status, NT_STATUS_OK);
264 smbcli_close(cli->tree, fnum);
266 status = smb_raw_rmdir(cli->tree, &dio);
267 CHECK_STATUS(status, NT_STATUS_OK);
269 printf("Testing with directory delete_on_close 1\n");
270 status = create_directory_handle(cli->tree, dname, &fnum);
271 CHECK_STATUS(status, NT_STATUS_OK);
273 sfinfo.disposition_info.in.file.fnum = fnum;
274 sfinfo.disposition_info.in.delete_on_close = 1;
275 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
276 CHECK_STATUS(status, NT_STATUS_OK);
278 smbcli_close(cli->tree, fnum);
280 status = smb_raw_rmdir(cli->tree, &dio);
281 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
284 if (!lp_parm_bool(-1, "torture", "samba3", False)) {
287 * Known deficiency, also skipped in base-delete.
290 printf("Testing with non-empty directory delete_on_close\n");
291 status = create_directory_handle(cli->tree, dname, &fnum);
292 CHECK_STATUS(status, NT_STATUS_OK);
294 fnum2 = create_complex_file(cli, mem_ctx, inside);
296 sfinfo.disposition_info.in.file.fnum = fnum;
297 sfinfo.disposition_info.in.delete_on_close = 1;
298 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
299 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
301 sfinfo.disposition_info.in.file.fnum = fnum2;
302 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
303 CHECK_STATUS(status, NT_STATUS_OK);
305 sfinfo.disposition_info.in.file.fnum = fnum;
306 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
307 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
309 smbcli_close(cli->tree, fnum2);
311 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
312 CHECK_STATUS(status, NT_STATUS_OK);
314 smbcli_close(cli->tree, fnum);
316 status = smb_raw_rmdir(cli->tree, &dio);
317 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
320 printf("Testing open dir with delete_on_close\n");
321 status = create_directory_handle(cli->tree, dname, &fnum);
322 CHECK_STATUS(status, NT_STATUS_OK);
324 smbcli_close(cli->tree, fnum);
325 fnum2 = create_complex_file(cli, mem_ctx, inside);
326 smbcli_close(cli->tree, fnum2);
328 op.generic.level = RAW_OPEN_NTCREATEX;
329 op.ntcreatex.in.root_fid = 0;
330 op.ntcreatex.in.flags = 0;
331 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
332 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
333 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
334 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
335 op.ntcreatex.in.alloc_size = 0;
336 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
337 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
338 op.ntcreatex.in.security_flags = 0;
339 op.ntcreatex.in.fname = dname;
341 status = smb_raw_open(cli->tree, mem_ctx, &op);
342 CHECK_STATUS(status, NT_STATUS_OK);
343 fnum = op.ntcreatex.out.file.fnum;
345 smbcli_close(cli->tree, fnum);
347 status = smb_raw_rmdir(cli->tree, &dio);
348 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
350 smbcli_deltree(cli->tree, dname);
352 printf("Testing double open dir with second delete_on_close\n");
353 status = create_directory_handle(cli->tree, dname, &fnum);
354 CHECK_STATUS(status, NT_STATUS_OK);
355 smbcli_close(cli->tree, fnum);
357 fnum2 = create_complex_file(cli, mem_ctx, inside);
358 smbcli_close(cli->tree, fnum2);
360 op.generic.level = RAW_OPEN_NTCREATEX;
361 op.ntcreatex.in.root_fid = 0;
362 op.ntcreatex.in.flags = 0;
363 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
364 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
365 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
366 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
367 op.ntcreatex.in.alloc_size = 0;
368 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
369 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
370 op.ntcreatex.in.security_flags = 0;
371 op.ntcreatex.in.fname = dname;
373 status = smb_raw_open(cli->tree, mem_ctx, &op);
374 CHECK_STATUS(status, NT_STATUS_OK);
375 fnum2 = op.ntcreatex.out.file.fnum;
377 smbcli_close(cli->tree, fnum2);
379 status = smb_raw_rmdir(cli->tree, &dio);
380 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
382 smbcli_deltree(cli->tree, dname);
384 printf("Testing pre-existing open dir with second delete_on_close\n");
385 status = create_directory_handle(cli->tree, dname, &fnum);
386 CHECK_STATUS(status, NT_STATUS_OK);
388 smbcli_close(cli->tree, fnum);
390 fnum = create_complex_file(cli, mem_ctx, inside);
391 smbcli_close(cli->tree, fnum);
393 /* we have a dir with a file in it, no handles open */
395 op.generic.level = RAW_OPEN_NTCREATEX;
396 op.ntcreatex.in.root_fid = 0;
397 op.ntcreatex.in.flags = 0;
398 op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
399 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
400 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
401 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
402 op.ntcreatex.in.alloc_size = 0;
403 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
404 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
405 op.ntcreatex.in.security_flags = 0;
406 op.ntcreatex.in.fname = dname;
408 status = smb_raw_open(cli->tree, mem_ctx, &op);
409 CHECK_STATUS(status, NT_STATUS_OK);
410 fnum = op.ntcreatex.out.file.fnum;
412 /* open without delete on close */
413 op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
414 status = smb_raw_open(cli->tree, mem_ctx, &op);
415 CHECK_STATUS(status, NT_STATUS_OK);
416 fnum2 = op.ntcreatex.out.file.fnum;
418 /* close 2nd file handle */
419 smbcli_close(cli->tree, fnum2);
421 status = smb_raw_rmdir(cli->tree, &dio);
422 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
425 smbcli_close(cli->tree, fnum);
427 status = smb_raw_rmdir(cli->tree, &dio);
428 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
431 smb_raw_exit(cli->session);
432 smbcli_deltree(cli->tree, BASEDIR);
438 basic testing of unlink calls
440 BOOL torture_raw_unlink(struct torture_context *torture)
442 struct smbcli_state *cli;
446 if (!torture_open_connection(&cli, 0)) {
450 mem_ctx = talloc_init("torture_raw_unlink");
452 ret &= test_unlink(cli, mem_ctx);
453 ret &= test_delete_on_close(cli, mem_ctx);
455 torture_close_connection(cli);
456 talloc_free(mem_ctx);