Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
[amitay/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/raw/raw_proto.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "param/param.h"
28
29 #define CHECK_STATUS(status, correct) do { \
30         if (!NT_STATUS_EQUAL(status, correct)) { \
31                 printf("(%s) Incorrect status %s - should be %s\n", \
32                        __location__, nt_errstr(status), nt_errstr(correct)); \
33                 ret = false; \
34                 goto done; \
35         }} while (0)
36
37 #define BASEDIR "\\testunlink"
38
39 /*
40   test unlink ops
41 */
42 static bool test_unlink(struct torture_context *tctx, struct smbcli_state *cli)
43 {
44         union smb_unlink io;
45         NTSTATUS status;
46         bool ret = true;
47         const char *fname = BASEDIR "\\test.txt";
48
49         if (!torture_setup_dir(cli, BASEDIR)) {
50                 return false;
51         }
52
53         printf("Trying non-existant file\n");
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_OBJECT_NAME_NOT_FOUND);
58
59         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
60
61         io.unlink.in.pattern = fname;
62         io.unlink.in.attrib = 0;
63         status = smb_raw_unlink(cli->tree, &io);
64         CHECK_STATUS(status, NT_STATUS_OK);
65
66         printf("Trying a hidden file\n");
67         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
68         torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
69
70         io.unlink.in.pattern = fname;
71         io.unlink.in.attrib = 0;
72         status = smb_raw_unlink(cli->tree, &io);
73         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
74
75         io.unlink.in.pattern = fname;
76         io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
77         status = smb_raw_unlink(cli->tree, &io);
78         CHECK_STATUS(status, NT_STATUS_OK);
79
80         io.unlink.in.pattern = fname;
81         io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
82         status = smb_raw_unlink(cli->tree, &io);
83         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
84
85         printf("Trying a directory\n");
86         io.unlink.in.pattern = BASEDIR;
87         io.unlink.in.attrib = 0;
88         status = smb_raw_unlink(cli->tree, &io);
89         CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
90
91         io.unlink.in.pattern = BASEDIR;
92         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
93         status = smb_raw_unlink(cli->tree, &io);
94         CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
95
96         printf("Trying a bad path\n");
97         io.unlink.in.pattern = "..";
98         io.unlink.in.attrib = 0;
99         status = smb_raw_unlink(cli->tree, &io);
100         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
101
102         io.unlink.in.pattern = "\\..";
103         io.unlink.in.attrib = 0;
104         status = smb_raw_unlink(cli->tree, &io);
105         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
106
107         io.unlink.in.pattern = BASEDIR "\\..\\..";
108         io.unlink.in.attrib = 0;
109         status = smb_raw_unlink(cli->tree, &io);
110         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
111
112         io.unlink.in.pattern = BASEDIR "\\..";
113         io.unlink.in.attrib = 0;
114         status = smb_raw_unlink(cli->tree, &io);
115         CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
116
117         printf("Trying wildcards\n");
118         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
119         io.unlink.in.pattern = BASEDIR "\\t*.t";
120         io.unlink.in.attrib = 0;
121         status = smb_raw_unlink(cli->tree, &io);
122         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
123
124         io.unlink.in.pattern = BASEDIR "\\z*";
125         io.unlink.in.attrib = 0;
126         status = smb_raw_unlink(cli->tree, &io);
127         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
128
129         io.unlink.in.pattern = BASEDIR "\\z*";
130         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
131         status = smb_raw_unlink(cli->tree, &io);
132
133         if (torture_setting_bool(tctx, "samba3", false)) {
134                 /*
135                  * In Samba3 we gave up upon getting the error codes in
136                  * wildcard unlink correct. Trying gentest showed that this is
137                  * irregular beyond our capabilities. So for
138                  * FILE_ATTRIBUTE_DIRECTORY we always return NAME_INVALID.
139                  * Tried by jra and vl. If others feel like solving this
140                  * puzzle, please tell us :-)
141                  */
142                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
143         }
144         else {
145                 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
146         }
147
148         io.unlink.in.pattern = BASEDIR "\\*";
149         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
150         status = smb_raw_unlink(cli->tree, &io);
151         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
152
153         io.unlink.in.pattern = BASEDIR "\\?";
154         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
155         status = smb_raw_unlink(cli->tree, &io);
156         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
157
158         io.unlink.in.pattern = BASEDIR "\\t*";
159         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
160         status = smb_raw_unlink(cli->tree, &io);
161         if (torture_setting_bool(tctx, "samba3", false)) {
162                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
163         }
164         else {
165                 CHECK_STATUS(status, NT_STATUS_OK);
166         }
167
168         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
169
170         io.unlink.in.pattern = BASEDIR "\\*.dat";
171         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
172         status = smb_raw_unlink(cli->tree, &io);
173         if (torture_setting_bool(tctx, "samba3", false)) {
174                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
175         }
176         else {
177                 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
178         }
179
180         io.unlink.in.pattern = BASEDIR "\\*.tx?";
181         io.unlink.in.attrib = 0;
182         status = smb_raw_unlink(cli->tree, &io);
183         if (torture_setting_bool(tctx, "samba3", false)) {
184                 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
185         }
186         else {
187                 CHECK_STATUS(status, NT_STATUS_OK);
188         }
189
190         status = smb_raw_unlink(cli->tree, &io);
191         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
192
193
194 done:
195         smb_raw_exit(cli->session);
196         smbcli_deltree(cli->tree, BASEDIR);
197         return ret;
198 }
199
200
201 /*
202   test delete on close 
203 */
204 static bool test_delete_on_close(struct torture_context *tctx, 
205                                                                  struct smbcli_state *cli)
206 {
207         union smb_open op;
208         union smb_unlink io;
209         struct smb_rmdir dio;
210         NTSTATUS status;
211         bool ret = true;
212         int fnum, fnum2;
213         const char *fname = BASEDIR "\\test.txt";
214         const char *dname = BASEDIR "\\test.dir";
215         const char *inside = BASEDIR "\\test.dir\\test.txt";
216         union smb_setfileinfo sfinfo;
217
218         if (!torture_setup_dir(cli, BASEDIR)) {
219                 return false;
220         }
221
222         dio.in.path = dname;
223
224         io.unlink.in.pattern = fname;
225         io.unlink.in.attrib = 0;
226         status = smb_raw_unlink(cli->tree, &io);
227         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
228
229         printf("Testing with delete_on_close 0\n");
230         fnum = create_complex_file(cli, tctx, fname);
231
232         sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
233         sfinfo.disposition_info.in.file.fnum = fnum;
234         sfinfo.disposition_info.in.delete_on_close = 0;
235         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
236         CHECK_STATUS(status, NT_STATUS_OK);
237
238         smbcli_close(cli->tree, fnum);
239
240         status = smb_raw_unlink(cli->tree, &io);
241         CHECK_STATUS(status, NT_STATUS_OK);
242
243         printf("Testing with delete_on_close 1\n");
244         fnum = create_complex_file(cli, tctx, fname);
245         sfinfo.disposition_info.in.file.fnum = fnum;
246         sfinfo.disposition_info.in.delete_on_close = 1;
247         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
248         CHECK_STATUS(status, NT_STATUS_OK);
249
250         smbcli_close(cli->tree, fnum);
251
252         status = smb_raw_unlink(cli->tree, &io);
253         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
254
255
256         printf("Testing with directory and delete_on_close 0\n");
257         status = create_directory_handle(cli->tree, dname, &fnum);
258         CHECK_STATUS(status, NT_STATUS_OK);
259
260         sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
261         sfinfo.disposition_info.in.file.fnum = fnum;
262         sfinfo.disposition_info.in.delete_on_close = 0;
263         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
264         CHECK_STATUS(status, NT_STATUS_OK);
265
266         smbcli_close(cli->tree, fnum);
267
268         status = smb_raw_rmdir(cli->tree, &dio);
269         CHECK_STATUS(status, NT_STATUS_OK);
270
271         printf("Testing with directory delete_on_close 1\n");
272         status = create_directory_handle(cli->tree, dname, &fnum);
273         CHECK_STATUS(status, NT_STATUS_OK);
274         
275         sfinfo.disposition_info.in.file.fnum = fnum;
276         sfinfo.disposition_info.in.delete_on_close = 1;
277         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
278         CHECK_STATUS(status, NT_STATUS_OK);
279
280         smbcli_close(cli->tree, fnum);
281
282         status = smb_raw_rmdir(cli->tree, &dio);
283         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
284
285
286         if (!torture_setting_bool(tctx, "samba3", false)) {
287
288                 /*
289                  * Known deficiency, also skipped in base-delete.
290                  */
291
292                 printf("Testing with non-empty directory delete_on_close\n");
293                 status = create_directory_handle(cli->tree, dname, &fnum);
294                 CHECK_STATUS(status, NT_STATUS_OK);
295
296                 fnum2 = create_complex_file(cli, tctx, inside);
297
298                 sfinfo.disposition_info.in.file.fnum = fnum;
299                 sfinfo.disposition_info.in.delete_on_close = 1;
300                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
301                 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
302
303                 sfinfo.disposition_info.in.file.fnum = fnum2;
304                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
305                 CHECK_STATUS(status, NT_STATUS_OK);
306
307                 sfinfo.disposition_info.in.file.fnum = fnum;
308                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
309                 CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
310
311                 smbcli_close(cli->tree, fnum2);
312
313                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
314                 CHECK_STATUS(status, NT_STATUS_OK);
315
316                 smbcli_close(cli->tree, fnum);
317
318                 status = smb_raw_rmdir(cli->tree, &dio);
319                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
320         }
321
322         printf("Testing open dir with delete_on_close\n");
323         status = create_directory_handle(cli->tree, dname, &fnum);
324         CHECK_STATUS(status, NT_STATUS_OK);
325         
326         smbcli_close(cli->tree, fnum);
327         fnum2 = create_complex_file(cli, tctx, inside);
328         smbcli_close(cli->tree, fnum2);
329
330         op.generic.level = RAW_OPEN_NTCREATEX;
331         op.ntcreatex.in.root_fid = 0;
332         op.ntcreatex.in.flags = 0;
333         op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
334         op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
335         op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
336         op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
337         op.ntcreatex.in.alloc_size = 0;
338         op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
339         op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
340         op.ntcreatex.in.security_flags = 0;
341         op.ntcreatex.in.fname = dname;
342
343         status = smb_raw_open(cli->tree, tctx, &op);
344         CHECK_STATUS(status, NT_STATUS_OK);
345         fnum = op.ntcreatex.out.file.fnum;
346
347         smbcli_close(cli->tree, fnum);
348
349         status = smb_raw_rmdir(cli->tree, &dio);
350         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
351
352         smbcli_deltree(cli->tree, dname);
353
354         printf("Testing double open dir with second delete_on_close\n");
355         status = create_directory_handle(cli->tree, dname, &fnum);
356         CHECK_STATUS(status, NT_STATUS_OK);
357         smbcli_close(cli->tree, fnum);
358         
359         fnum2 = create_complex_file(cli, tctx, inside);
360         smbcli_close(cli->tree, fnum2);
361
362         op.generic.level = RAW_OPEN_NTCREATEX;
363         op.ntcreatex.in.root_fid = 0;
364         op.ntcreatex.in.flags = 0;
365         op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
366         op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
367         op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
368         op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
369         op.ntcreatex.in.alloc_size = 0;
370         op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
371         op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
372         op.ntcreatex.in.security_flags = 0;
373         op.ntcreatex.in.fname = dname;
374
375         status = smb_raw_open(cli->tree, tctx, &op);
376         CHECK_STATUS(status, NT_STATUS_OK);
377         fnum2 = op.ntcreatex.out.file.fnum;
378
379         smbcli_close(cli->tree, fnum2);
380
381         status = smb_raw_rmdir(cli->tree, &dio);
382         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
383
384         smbcli_deltree(cli->tree, dname);
385
386         printf("Testing pre-existing open dir with second delete_on_close\n");
387         status = create_directory_handle(cli->tree, dname, &fnum);
388         CHECK_STATUS(status, NT_STATUS_OK);
389         
390         smbcli_close(cli->tree, fnum);
391
392         fnum = create_complex_file(cli, tctx, inside);
393         smbcli_close(cli->tree, fnum);
394
395         /* we have a dir with a file in it, no handles open */
396
397         op.generic.level = RAW_OPEN_NTCREATEX;
398         op.ntcreatex.in.root_fid = 0;
399         op.ntcreatex.in.flags = 0;
400         op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
401         op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
402         op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
403         op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
404         op.ntcreatex.in.alloc_size = 0;
405         op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
406         op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
407         op.ntcreatex.in.security_flags = 0;
408         op.ntcreatex.in.fname = dname;
409
410         status = smb_raw_open(cli->tree, tctx, &op);
411         CHECK_STATUS(status, NT_STATUS_OK);
412         fnum = op.ntcreatex.out.file.fnum;
413
414         /* open without delete on close */
415         op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
416         status = smb_raw_open(cli->tree, tctx, &op);
417         CHECK_STATUS(status, NT_STATUS_OK);
418         fnum2 = op.ntcreatex.out.file.fnum;
419
420         /* close 2nd file handle */
421         smbcli_close(cli->tree, fnum2);
422
423         status = smb_raw_rmdir(cli->tree, &dio);
424         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
425         
426
427         smbcli_close(cli->tree, fnum);
428
429         status = smb_raw_rmdir(cli->tree, &dio);
430         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
431         
432 done:
433         smb_raw_exit(cli->session);
434         smbcli_deltree(cli->tree, BASEDIR);
435         return ret;
436 }
437
438
439 /* 
440    basic testing of unlink calls
441 */
442 struct torture_suite *torture_raw_unlink(TALLOC_CTX *mem_ctx)
443 {
444         struct torture_suite *suite = torture_suite_create(mem_ctx, "UNLINK");
445
446         torture_suite_add_1smb_test(suite, "unlink", test_unlink);
447         torture_suite_add_1smb_test(suite, "delete_on_close", test_delete_on_close);
448
449         return suite;
450 }