63c163cfc194483823c2d066064d4ce25d3349d5
[metze/samba/wip.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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
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"
27
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)); \
32                 ret = False; \
33                 goto done; \
34         }} while (0)
35
36 #define BASEDIR "\\testunlink"
37
38 /*
39   test unlink ops
40 */
41 static BOOL test_unlink(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
42 {
43         union smb_unlink io;
44         NTSTATUS status;
45         BOOL ret = True;
46         const char *fname = BASEDIR "\\test.txt";
47
48         if (!torture_setup_dir(cli, BASEDIR)) {
49                 return False;
50         }
51
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);
57
58         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
59
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);
64
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);
68
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);
73
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);
78
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);
83
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);
89
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);
94
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);
100
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);
105
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);
110
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);
115
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);
122
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);
127
128         io.unlink.in.pattern = BASEDIR "\\z*";
129         io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
130         status = smb_raw_unlink(cli->tree, &io);
131
132         if (lp_parm_bool(-1, "torture", "samba3", False)) {
133                 /*
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 :-)
140                  */
141                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
142         }
143         else {
144                 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
145         }
146
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);
151
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);
156
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);
162         }
163         else {
164                 CHECK_STATUS(status, NT_STATUS_OK);
165         }
166
167         smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
168
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);
174         }
175         else {
176                 CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
177         }
178
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);
184         }
185         else {
186                 CHECK_STATUS(status, NT_STATUS_OK);
187         }
188
189         status = smb_raw_unlink(cli->tree, &io);
190         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
191
192
193 done:
194         smb_raw_exit(cli->session);
195         smbcli_deltree(cli->tree, BASEDIR);
196         return ret;
197 }
198
199
200 /*
201   test delete on close 
202 */
203 static BOOL test_delete_on_close(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
204 {
205         union smb_open op;
206         union smb_unlink io;
207         struct smb_rmdir dio;
208         NTSTATUS status;
209         BOOL ret = True;
210         int fnum, fnum2;
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;
215
216         if (!torture_setup_dir(cli, BASEDIR)) {
217                 return False;
218         }
219
220         dio.in.path = dname;
221
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);
226
227         printf("Testing with delete_on_close 0\n");
228         fnum = create_complex_file(cli, mem_ctx, fname);
229
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);
235
236         smbcli_close(cli->tree, fnum);
237
238         status = smb_raw_unlink(cli->tree, &io);
239         CHECK_STATUS(status, NT_STATUS_OK);
240
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);
247
248         smbcli_close(cli->tree, fnum);
249
250         status = smb_raw_unlink(cli->tree, &io);
251         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
252
253
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);
257
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);
263
264         smbcli_close(cli->tree, fnum);
265
266         status = smb_raw_rmdir(cli->tree, &dio);
267         CHECK_STATUS(status, NT_STATUS_OK);
268
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);
272         
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);
277
278         smbcli_close(cli->tree, fnum);
279
280         status = smb_raw_rmdir(cli->tree, &dio);
281         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
282
283
284         if (!lp_parm_bool(-1, "torture", "samba3", False)) {
285
286                 /*
287                  * Known deficiency, also skipped in base-delete.
288                  */
289
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);
293
294                 fnum2 = create_complex_file(cli, mem_ctx, inside);
295
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);
300
301                 sfinfo.disposition_info.in.file.fnum = fnum2;
302                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
303                 CHECK_STATUS(status, NT_STATUS_OK);
304
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);
308
309                 smbcli_close(cli->tree, fnum2);
310
311                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
312                 CHECK_STATUS(status, NT_STATUS_OK);
313
314                 smbcli_close(cli->tree, fnum);
315
316                 status = smb_raw_rmdir(cli->tree, &dio);
317                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
318         }
319
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);
323         
324         smbcli_close(cli->tree, fnum);
325         fnum2 = create_complex_file(cli, mem_ctx, inside);
326         smbcli_close(cli->tree, fnum2);
327
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;
340
341         status = smb_raw_open(cli->tree, mem_ctx, &op);
342         CHECK_STATUS(status, NT_STATUS_OK);
343         fnum = op.ntcreatex.out.file.fnum;
344
345         smbcli_close(cli->tree, fnum);
346
347         status = smb_raw_rmdir(cli->tree, &dio);
348         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
349
350         smbcli_deltree(cli->tree, dname);
351
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);
356         
357         fnum2 = create_complex_file(cli, mem_ctx, inside);
358         smbcli_close(cli->tree, fnum2);
359
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;
372
373         status = smb_raw_open(cli->tree, mem_ctx, &op);
374         CHECK_STATUS(status, NT_STATUS_OK);
375         fnum2 = op.ntcreatex.out.file.fnum;
376
377         smbcli_close(cli->tree, fnum2);
378
379         status = smb_raw_rmdir(cli->tree, &dio);
380         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
381
382         smbcli_deltree(cli->tree, dname);
383
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);
387         
388         smbcli_close(cli->tree, fnum);
389
390         fnum = create_complex_file(cli, mem_ctx, inside);
391         smbcli_close(cli->tree, fnum);
392
393         /* we have a dir with a file in it, no handles open */
394
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;
407
408         status = smb_raw_open(cli->tree, mem_ctx, &op);
409         CHECK_STATUS(status, NT_STATUS_OK);
410         fnum = op.ntcreatex.out.file.fnum;
411
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;
417
418         /* close 2nd file handle */
419         smbcli_close(cli->tree, fnum2);
420
421         status = smb_raw_rmdir(cli->tree, &dio);
422         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
423         
424
425         smbcli_close(cli->tree, fnum);
426
427         status = smb_raw_rmdir(cli->tree, &dio);
428         CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
429         
430 done:
431         smb_raw_exit(cli->session);
432         smbcli_deltree(cli->tree, BASEDIR);
433         return ret;
434 }
435
436
437 /* 
438    basic testing of unlink calls
439 */
440 BOOL torture_raw_unlink(struct torture_context *torture)
441 {
442         struct smbcli_state *cli;
443         BOOL ret = True;
444         TALLOC_CTX *mem_ctx;
445
446         if (!torture_open_connection(&cli, 0)) {
447                 return False;
448         }
449
450         mem_ctx = talloc_init("torture_raw_unlink");
451
452         ret &= test_unlink(cli, mem_ctx);
453         ret &= test_delete_on_close(cli, mem_ctx);
454
455         torture_close_connection(cli);
456         talloc_free(mem_ctx);
457         return ret;
458 }