r23792: convert Samba4 to GPLv3
[kai/samba.git] / source4 / torture / raw / unlink.c
1 /* 
2    Unix SMB/CIFS implementation.
3    unlink test suite
4    Copyright (C) Andrew Tridgell 2003
5    
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.
10    
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.
15    
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/>.
18 */
19
20 #include "includes.h"
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"
26
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)); \
31                 ret = False; \
32                 goto done; \
33         }} while (0)
34
35 #define BASEDIR "\\testunlink"
36
37 /*
38   test unlink ops
39 */
40 static BOOL test_unlink(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
41 {
42         union smb_unlink io;
43         NTSTATUS status;
44         BOOL ret = True;
45         const char *fname = BASEDIR "\\test.txt";
46
47         if (!torture_setup_dir(cli, BASEDIR)) {
48                 return False;
49         }
50
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);
56
57         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
58
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);
63
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);
67
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);
72
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);
77
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);
82
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);
88
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);
93
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);
99
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);
104
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);
109
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);
114
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);
121
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);
126
127         io.unlink.in.pattern = BASEDIR "\\z*";
128         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
129         status = smb_raw_unlink(cli->tree, &io);
130
131         if (lp_parm_bool(-1, "torture", "samba3", False)) {
132                 /*
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 :-)
139                  */
140                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
141         }
142         else {
143                 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
144         }
145
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);
150
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);
155
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);
161         }
162         else {
163                 CHECK_STATUS(status, NT_STATUS_OK);
164         }
165
166         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
167
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);
173         }
174         else {
175                 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
176         }
177
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);
183         }
184         else {
185                 CHECK_STATUS(status, NT_STATUS_OK);
186         }
187
188         status = smb_raw_unlink(cli->tree, &io);
189         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
190
191
192 done:
193         smb_raw_exit(cli->session);
194         smbcli_deltree(cli->tree, BASEDIR);
195         return ret;
196 }
197
198
199 /*
200   test delete on close 
201 */
202 static BOOL test_delete_on_close(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
203 {
204         union smb_open op;
205         union smb_unlink io;
206         struct smb_rmdir dio;
207         NTSTATUS status;
208         BOOL ret = True;
209         int fnum, fnum2;
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;
214
215         if (!torture_setup_dir(cli, BASEDIR)) {
216                 return False;
217         }
218
219         dio.in.path = dname;
220
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);
225
226         printf("Testing with delete_on_close 0\n");
227         fnum = create_complex_file(cli, mem_ctx, fname);
228
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);
234
235         smbcli_close(cli->tree, fnum);
236
237         status = smb_raw_unlink(cli->tree, &io);
238         CHECK_STATUS(status, NT_STATUS_OK);
239
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);
246
247         smbcli_close(cli->tree, fnum);
248
249         status = smb_raw_unlink(cli->tree, &io);
250         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
251
252
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);
256
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);
262
263         smbcli_close(cli->tree, fnum);
264
265         status = smb_raw_rmdir(cli->tree, &dio);
266         CHECK_STATUS(status, NT_STATUS_OK);
267
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);
271         
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);
276
277         smbcli_close(cli->tree, fnum);
278
279         status = smb_raw_rmdir(cli->tree, &dio);
280         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
281
282
283         if (!lp_parm_bool(-1, "torture", "samba3", False)) {
284
285                 /*
286                  * Known deficiency, also skipped in base-delete.
287                  */
288
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);
292
293                 fnum2 = create_complex_file(cli, mem_ctx, inside);
294
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);
299
300                 sfinfo.disposition_info.in.file.fnum = fnum2;
301                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
302                 CHECK_STATUS(status, NT_STATUS_OK);
303
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);
307
308                 smbcli_close(cli->tree, fnum2);
309
310                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
311                 CHECK_STATUS(status, NT_STATUS_OK);
312
313                 smbcli_close(cli->tree, fnum);
314
315                 status = smb_raw_rmdir(cli->tree, &dio);
316                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
317         }
318
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);
322         
323         smbcli_close(cli->tree, fnum);
324         fnum2 = create_complex_file(cli, mem_ctx, inside);
325         smbcli_close(cli->tree, fnum2);
326
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;
339
340         status = smb_raw_open(cli->tree, mem_ctx, &op);
341         CHECK_STATUS(status, NT_STATUS_OK);
342         fnum = op.ntcreatex.out.file.fnum;
343
344         smbcli_close(cli->tree, fnum);
345
346         status = smb_raw_rmdir(cli->tree, &dio);
347         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
348
349         smbcli_deltree(cli->tree, dname);
350
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);
355         
356         fnum2 = create_complex_file(cli, mem_ctx, inside);
357         smbcli_close(cli->tree, fnum2);
358
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;
371
372         status = smb_raw_open(cli->tree, mem_ctx, &op);
373         CHECK_STATUS(status, NT_STATUS_OK);
374         fnum2 = op.ntcreatex.out.file.fnum;
375
376         smbcli_close(cli->tree, fnum2);
377
378         status = smb_raw_rmdir(cli->tree, &dio);
379         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
380
381         smbcli_deltree(cli->tree, dname);
382
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);
386         
387         smbcli_close(cli->tree, fnum);
388
389         fnum = create_complex_file(cli, mem_ctx, inside);
390         smbcli_close(cli->tree, fnum);
391
392         /* we have a dir with a file in it, no handles open */
393
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;
406
407         status = smb_raw_open(cli->tree, mem_ctx, &op);
408         CHECK_STATUS(status, NT_STATUS_OK);
409         fnum = op.ntcreatex.out.file.fnum;
410
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;
416
417         /* close 2nd file handle */
418         smbcli_close(cli->tree, fnum2);
419
420         status = smb_raw_rmdir(cli->tree, &dio);
421         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
422         
423
424         smbcli_close(cli->tree, fnum);
425
426         status = smb_raw_rmdir(cli->tree, &dio);
427         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
428         
429 done:
430         smb_raw_exit(cli->session);
431         smbcli_deltree(cli->tree, BASEDIR);
432         return ret;
433 }
434
435
436 /* 
437    basic testing of unlink calls
438 */
439 BOOL torture_raw_unlink(struct torture_context *torture)
440 {
441         struct smbcli_state *cli;
442         BOOL ret = True;
443         TALLOC_CTX *mem_ctx;
444
445         if (!torture_open_connection(&cli, 0)) {
446                 return False;
447         }
448
449         mem_ctx = talloc_init("torture_raw_unlink");
450
451         ret &= test_unlink(cli, mem_ctx);
452         ret &= test_delete_on_close(cli, mem_ctx);
453
454         torture_close_connection(cli);
455         talloc_free(mem_ctx);
456         return ret;
457 }