r12693: Move core data structures out of smb.h into core.h
[samba.git] / source4 / torture / raw / open.c
1 /* 
2    Unix SMB/CIFS implementation.
3    RAW_OPEN_* individual 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 "libcli/raw/libcliraw.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "librpc/gen_ndr/ndr_security.h"
27 #include "lib/events/events.h"
28
29 /* enum for whether reads/writes are possible on a file */
30 enum rdwr_mode {RDWR_NONE, RDWR_RDONLY, RDWR_WRONLY, RDWR_RDWR};
31
32 #define BASEDIR "\\rawopen"
33
34 /*
35   check if a open file can be read/written
36 */
37 static enum rdwr_mode check_rdwr(struct smbcli_tree *tree, int fnum)
38 {
39         uint8_t c = 1;
40         BOOL can_read  = (smbcli_read(tree, fnum, &c, 0, 1) == 1);
41         BOOL can_write = (smbcli_write(tree, fnum, 0, &c, 0, 1) == 1);
42         if ( can_read &&  can_write) return RDWR_RDWR;
43         if ( can_read && !can_write) return RDWR_RDONLY;
44         if (!can_read &&  can_write) return RDWR_WRONLY;
45         return RDWR_NONE;
46 }
47
48 /*
49   describe a RDWR mode as a string
50 */
51 static const char *rdwr_string(enum rdwr_mode m)
52 {
53         switch (m) {
54         case RDWR_NONE: return "NONE";
55         case RDWR_RDONLY: return "RDONLY";
56         case RDWR_WRONLY: return "WRONLY";
57         case RDWR_RDWR: return "RDWR";
58         }
59         return "-";
60 }
61
62 #define CHECK_STATUS(status, correct) do { \
63         if (!NT_STATUS_EQUAL(status, correct)) { \
64                 printf("(%s) Incorrect status %s - should be %s\n", \
65                        __location__, nt_errstr(status), nt_errstr(correct)); \
66                 ret = False; \
67                 goto done; \
68         }} while (0)
69
70 #define CREATE_FILE do { \
71         fnum = create_complex_file(cli, mem_ctx, fname); \
72         if (fnum == -1) { \
73                 printf("(%s) Failed to create %s - %s\n", __location__, fname, smbcli_errstr(cli->tree)); \
74                 ret = False; \
75                 goto done; \
76         }} while (0)
77
78 #define CHECK_RDWR(fnum, correct) do { \
79         enum rdwr_mode m = check_rdwr(cli->tree, fnum); \
80         if (m != correct) { \
81                 printf("(%s) Incorrect readwrite mode %s - expected %s\n", \
82                        __location__, rdwr_string(m), rdwr_string(correct)); \
83                 ret = False; \
84         }} while (0)
85
86 #define CHECK_TIME(t, field) do { \
87         time_t t1, t2; \
88         finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
89         finfo.all_info.in.fname = fname; \
90         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
91         CHECK_STATUS(status, NT_STATUS_OK); \
92         t1 = t & ~1; \
93         t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
94         if (ABS(t1-t2) > 2) { \
95                 printf("(%s) wrong time for field %s  %s - %s\n", \
96                        __location__, #field, \
97                        timestring(mem_ctx, t1), \
98                        timestring(mem_ctx, t2)); \
99                 dump_all_info(mem_ctx, &finfo); \
100                 ret = False; \
101         }} while (0)
102
103 #define CHECK_NTTIME(t, field) do { \
104         NTTIME t2; \
105         finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
106         finfo.all_info.in.fname = fname; \
107         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
108         CHECK_STATUS(status, NT_STATUS_OK); \
109         t2 = finfo.all_info.out.field; \
110         if (t != t2) { \
111                 printf("(%s) wrong time for field %s  %s - %s\n", \
112                        __location__, #field, \
113                        nt_time_string(mem_ctx, t), \
114                        nt_time_string(mem_ctx, t2)); \
115                 dump_all_info(mem_ctx, &finfo); \
116                 ret = False; \
117         }} while (0)
118
119 #define CHECK_ALL_INFO(v, field) do { \
120         finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
121         finfo.all_info.in.fname = fname; \
122         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
123         CHECK_STATUS(status, NT_STATUS_OK); \
124         if ((v) != (finfo.all_info.out.field)) { \
125                 printf("(%s) wrong value for field %s  0x%x - 0x%x\n", \
126                        __location__, #field, (int)v, (int)(finfo.all_info.out.field)); \
127                 dump_all_info(mem_ctx, &finfo); \
128                 ret = False; \
129         }} while (0)
130
131 #define CHECK_VAL(v, correct) do { \
132         if ((v) != (correct)) { \
133                 printf("(%s) wrong value for %s  0x%x - should be 0x%x\n", \
134                        __location__, #v, (int)(v), (int)correct); \
135                 ret = False; \
136         }} while (0)
137
138 #define SET_ATTRIB(sattrib) do { \
139         union smb_setfileinfo sfinfo; \
140         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; \
141         sfinfo.generic.file.fname = fname; \
142         ZERO_STRUCT(sfinfo.basic_info.in); \
143         sfinfo.basic_info.in.attrib = sattrib; \
144         status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
145         if (!NT_STATUS_IS_OK(status)) { \
146                 printf("(%s) Failed to set attrib 0x%x on %s\n", \
147                        __location__, sattrib, fname); \
148         }} while (0)
149
150 /*
151   test RAW_OPEN_OPEN
152 */
153 static BOOL test_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
154 {
155         union smb_open io;
156         union smb_fileinfo finfo;
157         const char *fname = BASEDIR "\\torture_open.txt";
158         NTSTATUS status;
159         int fnum = -1, fnum2;
160         BOOL ret = True;
161
162         printf("Checking RAW_OPEN_OPEN\n");
163
164         io.openold.level = RAW_OPEN_OPEN;
165         io.openold.in.fname = fname;
166         io.openold.in.open_mode = OPEN_FLAGS_FCB;
167         io.openold.in.search_attrs = 0;
168         status = smb_raw_open(cli->tree, mem_ctx, &io);
169         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
170         fnum = io.openold.out.fnum;
171
172         smbcli_unlink(cli->tree, fname);
173         CREATE_FILE;
174         smbcli_close(cli->tree, fnum);
175
176         status = smb_raw_open(cli->tree, mem_ctx, &io);
177         CHECK_STATUS(status, NT_STATUS_OK);
178         fnum = io.openold.out.fnum;
179         CHECK_RDWR(fnum, RDWR_RDWR);
180
181         status = smb_raw_open(cli->tree, mem_ctx, &io);
182         CHECK_STATUS(status, NT_STATUS_OK);
183         fnum2 = io.openold.out.fnum;
184         CHECK_RDWR(fnum2, RDWR_RDWR);
185         smbcli_close(cli->tree, fnum2);
186         smbcli_close(cli->tree, fnum);
187
188         /* check the read/write modes */
189         io.openold.level = RAW_OPEN_OPEN;
190         io.openold.in.fname = fname;
191         io.openold.in.search_attrs = 0;
192
193         io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ;
194         status = smb_raw_open(cli->tree, mem_ctx, &io);
195         CHECK_STATUS(status, NT_STATUS_OK);
196         fnum = io.openold.out.fnum;
197         CHECK_RDWR(fnum, RDWR_RDONLY);
198         smbcli_close(cli->tree, fnum);
199
200         io.openold.in.open_mode = OPEN_FLAGS_OPEN_WRITE;
201         status = smb_raw_open(cli->tree, mem_ctx, &io);
202         CHECK_STATUS(status, NT_STATUS_OK);
203         fnum = io.openold.out.fnum;
204         CHECK_RDWR(fnum, RDWR_WRONLY);
205         smbcli_close(cli->tree, fnum);
206
207         io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR;
208         status = smb_raw_open(cli->tree, mem_ctx, &io);
209         CHECK_STATUS(status, NT_STATUS_OK);
210         fnum = io.openold.out.fnum;
211         CHECK_RDWR(fnum, RDWR_RDWR);
212         smbcli_close(cli->tree, fnum);
213
214         /* check the share modes roughly - not a complete matrix */
215         io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR | OPEN_FLAGS_DENY_WRITE;
216         status = smb_raw_open(cli->tree, mem_ctx, &io);
217         CHECK_STATUS(status, NT_STATUS_OK);
218         fnum = io.openold.out.fnum;
219         CHECK_RDWR(fnum, RDWR_RDWR);
220         
221         if (io.openold.in.open_mode != io.openold.out.rmode) {
222                 printf("(%s) rmode should equal open_mode - 0x%x 0x%x\n",
223                        __location__, io.openold.out.rmode, io.openold.in.open_mode);
224         }
225
226         io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR | OPEN_FLAGS_DENY_NONE;
227         status = smb_raw_open(cli->tree, mem_ctx, &io);
228         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
229
230         io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ | OPEN_FLAGS_DENY_NONE;
231         status = smb_raw_open(cli->tree, mem_ctx, &io);
232         CHECK_STATUS(status, NT_STATUS_OK);
233         fnum2 = io.openold.out.fnum;
234         CHECK_RDWR(fnum2, RDWR_RDONLY);
235         smbcli_close(cli->tree, fnum);
236         smbcli_close(cli->tree, fnum2);
237
238
239         /* check the returned write time */
240         io.openold.level = RAW_OPEN_OPEN;
241         io.openold.in.fname = fname;
242         io.openold.in.search_attrs = 0;
243         io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ;
244         status = smb_raw_open(cli->tree, mem_ctx, &io);
245         CHECK_STATUS(status, NT_STATUS_OK);
246         fnum = io.openold.out.fnum;
247
248         /* check other reply fields */
249         CHECK_TIME(io.openold.out.write_time, write_time);
250         CHECK_ALL_INFO(io.openold.out.size, size);
251         CHECK_ALL_INFO(io.openold.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
252
253 done:
254         smbcli_close(cli->tree, fnum);
255         smbcli_unlink(cli->tree, fname);
256
257         return ret;
258 }
259
260
261 /*
262   test RAW_OPEN_OPENX
263 */
264 static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
265 {
266         union smb_open io;
267         union smb_fileinfo finfo;
268         const char *fname = BASEDIR "\\torture_openx.txt";
269         const char *fname_exe = BASEDIR "\\torture_openx.exe";
270         NTSTATUS status;
271         int fnum = -1, fnum2;
272         BOOL ret = True;
273         int i;
274         struct timeval tv;
275         struct {
276                 uint16_t open_func;
277                 BOOL with_file;
278                 NTSTATUS correct_status;
279         } open_funcs[] = {
280                 { OPENX_OPEN_FUNC_OPEN,                           True,  NT_STATUS_OK },
281                 { OPENX_OPEN_FUNC_OPEN,                           False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
282                 { OPENX_OPEN_FUNC_OPEN  | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OK },
283                 { OPENX_OPEN_FUNC_OPEN  | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
284                 { OPENX_OPEN_FUNC_FAIL,                           True,  NT_STATUS_DOS(ERRDOS, ERRbadaccess) },
285                 { OPENX_OPEN_FUNC_FAIL,                           False, NT_STATUS_DOS(ERRDOS, ERRbadaccess) },
286                 { OPENX_OPEN_FUNC_FAIL  | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OBJECT_NAME_COLLISION },
287                 { OPENX_OPEN_FUNC_FAIL  | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
288                 { OPENX_OPEN_FUNC_TRUNC,                          True,  NT_STATUS_OK },
289                 { OPENX_OPEN_FUNC_TRUNC,                          False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
290                 { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OK },
291                 { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
292         };
293
294         printf("Checking RAW_OPEN_OPENX\n");
295         smbcli_unlink(cli->tree, fname);
296
297         io.openx.level = RAW_OPEN_OPENX;
298         io.openx.in.fname = fname;
299         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
300         io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
301         io.openx.in.search_attrs = 0;
302         io.openx.in.file_attrs = 0;
303         io.openx.in.write_time = 0;
304         io.openx.in.size = 1024*1024;
305         io.openx.in.timeout = 0;
306
307         /* check all combinations of open_func */
308         for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
309                 if (open_funcs[i].with_file) {
310                         fnum = create_complex_file(cli, mem_ctx, fname);
311                         if (fnum == -1) {
312                                 d_printf("Failed to create file %s - %s\n", fname, smbcli_errstr(cli->tree));
313                                 ret = False;
314                                 goto done;
315                         }
316                         smbcli_close(cli->tree, fnum);
317                 }
318                 io.openx.in.open_func = open_funcs[i].open_func;
319                 status = smb_raw_open(cli->tree, mem_ctx, &io);
320                 if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
321                         printf("(%s) incorrect status %s should be %s (i=%d with_file=%d open_func=0x%x)\n", 
322                                __location__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
323                                i, (int)open_funcs[i].with_file, (int)open_funcs[i].open_func);
324                         ret = False;
325                 }
326                 if (NT_STATUS_IS_OK(status)) {
327                         smbcli_close(cli->tree, io.openx.out.fnum);
328                 }
329                 if (open_funcs[i].with_file) {
330                         smbcli_unlink(cli->tree, fname);
331                 }
332         }
333
334         smbcli_unlink(cli->tree, fname);
335
336         /* check the basic return fields */
337         io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
338         status = smb_raw_open(cli->tree, mem_ctx, &io);
339         CHECK_STATUS(status, NT_STATUS_OK);
340         fnum = io.openx.out.fnum;
341
342         CHECK_ALL_INFO(io.openx.out.size, size);
343         CHECK_TIME(io.openx.out.write_time, write_time);
344         CHECK_ALL_INFO(io.openx.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
345         CHECK_VAL(io.openx.out.access, OPENX_MODE_ACCESS_RDWR);
346         CHECK_VAL(io.openx.out.ftype, 0);
347         CHECK_VAL(io.openx.out.devstate, 0);
348         CHECK_VAL(io.openx.out.action, OPENX_ACTION_CREATED);
349         CHECK_VAL(io.openx.out.size, 1024*1024);
350         CHECK_ALL_INFO(io.openx.in.size, size);
351         smbcli_close(cli->tree, fnum);
352         smbcli_unlink(cli->tree, fname);
353
354         /* check the fields when the file already existed */
355         fnum2 = create_complex_file(cli, mem_ctx, fname);
356         if (fnum2 == -1) {
357                 ret = False;
358                 goto done;
359         }
360         smbcli_close(cli->tree, fnum2);
361
362         io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
363         status = smb_raw_open(cli->tree, mem_ctx, &io);
364         CHECK_STATUS(status, NT_STATUS_OK);
365         fnum = io.openx.out.fnum;
366
367         CHECK_ALL_INFO(io.openx.out.size, size);
368         CHECK_TIME(io.openx.out.write_time, write_time);
369         CHECK_VAL(io.openx.out.action, OPENX_ACTION_EXISTED);
370         CHECK_VAL(io.openx.out.unknown, 0);
371         CHECK_ALL_INFO(io.openx.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
372         smbcli_close(cli->tree, fnum);
373
374         /* now check the search attrib for hidden files - win2003 ignores this? */
375         SET_ATTRIB(FILE_ATTRIBUTE_HIDDEN);
376         CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN, attrib);
377
378         io.openx.in.search_attrs = FILE_ATTRIBUTE_HIDDEN;
379         status = smb_raw_open(cli->tree, mem_ctx, &io);
380         CHECK_STATUS(status, NT_STATUS_OK);
381         smbcli_close(cli->tree, io.openx.out.fnum);
382
383         io.openx.in.search_attrs = 0;
384         status = smb_raw_open(cli->tree, mem_ctx, &io);
385         CHECK_STATUS(status, NT_STATUS_OK);
386         smbcli_close(cli->tree, io.openx.out.fnum);
387
388         SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
389         smbcli_unlink(cli->tree, fname);
390
391         /* and check attrib on create */
392         io.openx.in.open_func = OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE;
393         io.openx.in.search_attrs = 0;
394         io.openx.in.file_attrs = FILE_ATTRIBUTE_SYSTEM;
395         status = smb_raw_open(cli->tree, mem_ctx, &io);
396         CHECK_STATUS(status, NT_STATUS_OK);
397         CHECK_ALL_INFO(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE, 
398                        attrib & ~FILE_ATTRIBUTE_NONINDEXED);
399         smbcli_close(cli->tree, io.openx.out.fnum);
400         smbcli_unlink(cli->tree, fname);
401
402         /* check timeout on create - win2003 ignores the timeout! */
403         io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
404         io.openx.in.file_attrs = 0;
405         io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_ALL;
406         status = smb_raw_open(cli->tree, mem_ctx, &io);
407         CHECK_STATUS(status, NT_STATUS_OK);
408         fnum = io.openx.out.fnum;
409
410         io.openx.in.timeout = 20000;
411         tv = timeval_current();
412         io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_NONE;
413         status = smb_raw_open(cli->tree, mem_ctx, &io);
414         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
415         if (timeval_elapsed(&tv) > 3.0) {
416                 printf("(%s) Incorrect timing in openx with timeout - waited %.2f seconds\n",
417                        __location__, timeval_elapsed(&tv));
418                 ret = False;
419         }
420         smbcli_close(cli->tree, fnum);
421         smbcli_unlink(cli->tree, fname);
422
423         /* now this is a really weird one - open for execute implies create?! */
424         io.openx.in.fname = fname;
425         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
426         io.openx.in.open_mode = OPENX_MODE_ACCESS_EXEC | OPENX_MODE_DENY_NONE;
427         io.openx.in.search_attrs = 0;
428         io.openx.in.open_func = OPENX_OPEN_FUNC_FAIL;
429         io.openx.in.file_attrs = 0;
430         io.openx.in.write_time = 0;
431         io.openx.in.size = 0;
432         io.openx.in.timeout = 0;
433         status = smb_raw_open(cli->tree, mem_ctx, &io);
434         CHECK_STATUS(status, NT_STATUS_OK);
435         smbcli_close(cli->tree, io.openx.out.fnum);
436
437         /* check the extended return flag */
438         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO | OPENX_FLAGS_EXTENDED_RETURN;
439         io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
440         status = smb_raw_open(cli->tree, mem_ctx, &io);
441         CHECK_STATUS(status, NT_STATUS_OK);
442         CHECK_VAL(io.openx.out.access_mask, SEC_STD_ALL);
443         smbcli_close(cli->tree, io.openx.out.fnum);
444
445         io.openx.in.fname = "\\A.+,;=[].B";
446         status = smb_raw_open(cli->tree, mem_ctx, &io);
447         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
448
449         /* Check the mapping for open exec. */
450
451         /* First create an .exe file. */
452         smbcli_unlink(cli->tree, fname_exe);
453         fnum = create_complex_file(cli, mem_ctx, fname_exe);
454         smbcli_close(cli->tree, fnum);
455
456         io.openx.level = RAW_OPEN_OPENX;
457         io.openx.in.fname = fname_exe;
458         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
459         io.openx.in.open_mode = OPENX_MODE_ACCESS_EXEC | OPENX_MODE_DENY_NONE;
460         io.openx.in.search_attrs = 0;
461         io.openx.in.file_attrs = 0;
462         io.openx.in.write_time = 0;
463         io.openx.in.size = 0;
464         io.openx.in.timeout = 0;
465         status = smb_raw_open(cli->tree, mem_ctx, &io);
466         CHECK_STATUS(status, NT_STATUS_OK);
467
468         /* Can we read and write ? */
469         CHECK_RDWR(io.openx.out.fnum, RDWR_RDONLY);
470         smbcli_close(cli->tree, io.openx.out.fnum);
471         smbcli_unlink(cli->tree, fname);
472
473 done:
474         smbcli_close(cli->tree, fnum);
475         smbcli_unlink(cli->tree, fname_exe);
476         smbcli_unlink(cli->tree, fname);
477
478         return ret;
479 }
480
481
482 /*
483   test RAW_OPEN_T2OPEN
484
485   many thanks to kukks for a sniff showing how this works with os2->w2k
486 */
487 static BOOL test_t2open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
488 {
489         union smb_open io;
490         union smb_fileinfo finfo;
491         const char *fname1 = BASEDIR "\\torture_t2open_yes.txt";
492         const char *fname2 = BASEDIR "\\torture_t2open_no.txt";
493         const char *fname = BASEDIR "\\torture_t2open_3.txt";
494         NTSTATUS status;
495         int fnum;
496         BOOL ret = True;
497         int i;
498         struct {
499                 uint16_t open_func;
500                 BOOL with_file;
501                 NTSTATUS correct_status;
502         } open_funcs[] = {
503                 { OPENX_OPEN_FUNC_OPEN,                           True,  NT_STATUS_OK },
504                 { OPENX_OPEN_FUNC_OPEN,                           False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
505                 { OPENX_OPEN_FUNC_OPEN  | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OK },
506                 { OPENX_OPEN_FUNC_OPEN  | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
507                 { OPENX_OPEN_FUNC_FAIL,                           True,  NT_STATUS_OBJECT_NAME_COLLISION },
508                 { OPENX_OPEN_FUNC_FAIL,                           False, NT_STATUS_OBJECT_NAME_COLLISION },
509                 { OPENX_OPEN_FUNC_FAIL  | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OBJECT_NAME_COLLISION },
510                 { OPENX_OPEN_FUNC_FAIL  | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OBJECT_NAME_COLLISION },
511                 { OPENX_OPEN_FUNC_TRUNC,                          True,  NT_STATUS_OK },
512                 { OPENX_OPEN_FUNC_TRUNC,                          False, NT_STATUS_OK },
513                 { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OK },
514                 { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
515         };
516
517         fnum = create_complex_file(cli, mem_ctx, fname1);
518         if (fnum == -1) {
519                 d_printf("Failed to create file %s - %s\n", fname1, smbcli_errstr(cli->tree));
520                 ret = False;
521                 goto done;
522         }
523         smbcli_close(cli->tree, fnum);
524
525         printf("Checking RAW_OPEN_T2OPEN\n");
526
527         io.t2open.level = RAW_OPEN_T2OPEN;
528         io.t2open.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
529         io.t2open.in.open_mode = OPENX_MODE_DENY_NONE | OPENX_MODE_ACCESS_RDWR;
530         io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
531         io.t2open.in.search_attrs = 0;
532         io.t2open.in.file_attrs = 0;
533         io.t2open.in.write_time = 0;
534         io.t2open.in.size = 0;
535         io.t2open.in.timeout = 0;
536
537         io.t2open.in.num_eas = 3;
538         io.t2open.in.eas = talloc_array(mem_ctx, struct ea_struct, io.t2open.in.num_eas);
539         io.t2open.in.eas[0].flags = 0;
540         io.t2open.in.eas[0].name.s = ".CLASSINFO";
541         io.t2open.in.eas[0].value = data_blob_talloc(mem_ctx, "first value", 11);
542         io.t2open.in.eas[1].flags = 0;
543         io.t2open.in.eas[1].name.s = "EA TWO";
544         io.t2open.in.eas[1].value = data_blob_talloc(mem_ctx, "foo", 3);
545         io.t2open.in.eas[2].flags = 0;
546         io.t2open.in.eas[2].name.s = "X THIRD";
547         io.t2open.in.eas[2].value = data_blob_talloc(mem_ctx, "xy", 2);
548
549         /* check all combinations of open_func */
550         for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
551                 if (open_funcs[i].with_file) {
552                         io.t2open.in.fname = fname1;
553                 } else {
554                         io.t2open.in.fname = fname2;
555                 }
556                 io.t2open.in.open_func = open_funcs[i].open_func;
557                 status = smb_raw_open(cli->tree, mem_ctx, &io);
558                 if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
559                         printf("(%s) incorrect status %s should be %s (i=%d with_file=%d open_func=0x%x)\n", 
560                                __location__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
561                                i, (int)open_funcs[i].with_file, (int)open_funcs[i].open_func);
562                         ret = False;
563                 }
564                 if (NT_STATUS_IS_OK(status)) {
565                         smbcli_close(cli->tree, io.t2open.out.fnum);
566                 }
567         }
568
569         smbcli_unlink(cli->tree, fname1);
570         smbcli_unlink(cli->tree, fname2);
571
572         /* check the basic return fields */
573         io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
574         io.t2open.in.write_time = 0;
575         io.t2open.in.fname = fname;
576         status = smb_raw_open(cli->tree, mem_ctx, &io);
577         CHECK_STATUS(status, NT_STATUS_OK);
578         fnum = io.t2open.out.fnum;
579
580         CHECK_ALL_INFO(io.t2open.out.size, size);
581 #if 0
582         /* windows appears to leak uninitialised memory here */
583         CHECK_VAL(io.t2open.out.write_time, 0);
584 #endif
585         CHECK_ALL_INFO(io.t2open.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
586         CHECK_VAL(io.t2open.out.access, OPENX_MODE_DENY_NONE | OPENX_MODE_ACCESS_RDWR);
587         CHECK_VAL(io.t2open.out.ftype, 0);
588         CHECK_VAL(io.t2open.out.devstate, 0);
589         CHECK_VAL(io.t2open.out.action, OPENX_ACTION_CREATED);
590         smbcli_close(cli->tree, fnum);
591
592         status = torture_check_ea(cli, fname, ".CLASSINFO", "first value");
593         CHECK_STATUS(status, NT_STATUS_OK);
594         status = torture_check_ea(cli, fname, "EA TWO", "foo");
595         CHECK_STATUS(status, NT_STATUS_OK);
596         status = torture_check_ea(cli, fname, "X THIRD", "xy");
597         CHECK_STATUS(status, NT_STATUS_OK);
598
599         /* now check the search attrib for hidden files - win2003 ignores this? */
600         SET_ATTRIB(FILE_ATTRIBUTE_HIDDEN);
601         CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN, attrib);
602
603         status = smb_raw_open(cli->tree, mem_ctx, &io);
604         CHECK_STATUS(status, NT_STATUS_OK);
605         smbcli_close(cli->tree, io.t2open.out.fnum);
606
607         status = smb_raw_open(cli->tree, mem_ctx, &io);
608         CHECK_STATUS(status, NT_STATUS_OK);
609         smbcli_close(cli->tree, io.t2open.out.fnum);
610
611         SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
612         smbcli_unlink(cli->tree, fname);
613
614         /* and check attrib on create */
615         io.t2open.in.open_func = OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE;
616         io.t2open.in.file_attrs = FILE_ATTRIBUTE_SYSTEM;
617         status = smb_raw_open(cli->tree, mem_ctx, &io);
618         CHECK_STATUS(status, NT_STATUS_OK);
619
620         /* check timeout on create - win2003 ignores the timeout! */
621         io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
622         io.t2open.in.file_attrs = 0;
623         io.t2open.in.timeout = 20000;
624         io.t2open.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_ALL;
625         status = smb_raw_open(cli->tree, mem_ctx, &io);
626         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
627
628 done:
629         smbcli_close(cli->tree, fnum);
630         smbcli_unlink(cli->tree, fname);
631
632         return ret;
633 }
634         
635
636 /*
637   test RAW_OPEN_NTCREATEX
638 */
639 static BOOL test_ntcreatex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
640 {
641         union smb_open io;
642         union smb_fileinfo finfo;
643         const char *fname = BASEDIR "\\torture_ntcreatex.txt";
644         const char *dname = BASEDIR "\\torture_ntcreatex.dir";
645         NTSTATUS status;
646         int fnum = -1;
647         BOOL ret = True;
648         int i;
649         struct {
650                 uint32_t open_disp;
651                 BOOL with_file;
652                 NTSTATUS correct_status;
653         } open_funcs[] = {
654                 { NTCREATEX_DISP_SUPERSEDE,     True,  NT_STATUS_OK },
655                 { NTCREATEX_DISP_SUPERSEDE,     False, NT_STATUS_OK },
656                 { NTCREATEX_DISP_OPEN,          True,  NT_STATUS_OK },
657                 { NTCREATEX_DISP_OPEN,          False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
658                 { NTCREATEX_DISP_CREATE,        True,  NT_STATUS_OBJECT_NAME_COLLISION },
659                 { NTCREATEX_DISP_CREATE,        False, NT_STATUS_OK },
660                 { NTCREATEX_DISP_OPEN_IF,       True,  NT_STATUS_OK },
661                 { NTCREATEX_DISP_OPEN_IF,       False, NT_STATUS_OK },
662                 { NTCREATEX_DISP_OVERWRITE,     True,  NT_STATUS_OK },
663                 { NTCREATEX_DISP_OVERWRITE,     False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
664                 { NTCREATEX_DISP_OVERWRITE_IF,  True,  NT_STATUS_OK },
665                 { NTCREATEX_DISP_OVERWRITE_IF,  False, NT_STATUS_OK },
666                 { 6,                            True,  NT_STATUS_INVALID_PARAMETER },
667                 { 6,                            False, NT_STATUS_INVALID_PARAMETER },
668         };
669
670         printf("Checking RAW_OPEN_NTCREATEX\n");
671
672         /* reasonable default parameters */
673         io.generic.level = RAW_OPEN_NTCREATEX;
674         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
675         io.ntcreatex.in.root_fid = 0;
676         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
677         io.ntcreatex.in.alloc_size = 1024*1024;
678         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
679         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
680         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
681         io.ntcreatex.in.create_options = 0;
682         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
683         io.ntcreatex.in.security_flags = 0;
684         io.ntcreatex.in.fname = fname;
685
686         /* test the open disposition */
687         for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
688                 if (open_funcs[i].with_file) {
689                         fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR|O_TRUNC, DENY_NONE);
690                         if (fnum == -1) {
691                                 d_printf("Failed to create file %s - %s\n", fname, smbcli_errstr(cli->tree));
692                                 ret = False;
693                                 goto done;
694                         }
695                         smbcli_close(cli->tree, fnum);
696                 }
697                 io.ntcreatex.in.open_disposition = open_funcs[i].open_disp;
698                 status = smb_raw_open(cli->tree, mem_ctx, &io);
699                 if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
700                         printf("(%s) incorrect status %s should be %s (i=%d with_file=%d open_disp=%d)\n", 
701                                __location__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
702                                i, (int)open_funcs[i].with_file, (int)open_funcs[i].open_disp);
703                         ret = False;
704                 }
705                 if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
706                         smbcli_close(cli->tree, io.ntcreatex.out.fnum);
707                         smbcli_unlink(cli->tree, fname);
708                 }
709         }
710
711         /* basic field testing */
712         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
713
714         status = smb_raw_open(cli->tree, mem_ctx, &io);
715         CHECK_STATUS(status, NT_STATUS_OK);
716         fnum = io.ntcreatex.out.fnum;
717
718         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
719         CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
720         CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
721         CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
722         CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
723         CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
724         CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
725         CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
726         CHECK_ALL_INFO(io.ntcreatex.out.size, size);
727         CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
728         CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
729
730         /* check fields when the file already existed */
731         smbcli_close(cli->tree, fnum);
732         smbcli_unlink(cli->tree, fname);
733         fnum = create_complex_file(cli, mem_ctx, fname);
734         if (fnum == -1) {
735                 ret = False;
736                 goto done;
737         }
738         smbcli_close(cli->tree, fnum);
739
740         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
741         status = smb_raw_open(cli->tree, mem_ctx, &io);
742         CHECK_STATUS(status, NT_STATUS_OK);
743         fnum = io.ntcreatex.out.fnum;
744
745         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
746         CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
747         CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
748         CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
749         CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
750         CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
751         CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
752         CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
753         CHECK_ALL_INFO(io.ntcreatex.out.size, size);
754         CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
755         CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
756         smbcli_close(cli->tree, fnum);
757         smbcli_unlink(cli->tree, fname);
758
759
760         /* create a directory */
761         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
762         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
763         io.ntcreatex.in.alloc_size = 0;
764         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
765         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
766         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
767         io.ntcreatex.in.create_options = 0;
768         io.ntcreatex.in.fname = dname;
769         fname = dname;
770
771         smbcli_rmdir(cli->tree, fname);
772         smbcli_unlink(cli->tree, fname);
773
774         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
775         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
776         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
777         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
778         status = smb_raw_open(cli->tree, mem_ctx, &io);
779         CHECK_STATUS(status, NT_STATUS_OK);
780         fnum = io.ntcreatex.out.fnum;
781
782         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
783         CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
784         CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
785         CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
786         CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
787         CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
788         CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
789         CHECK_VAL(io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, 
790                   FILE_ATTRIBUTE_DIRECTORY);
791         CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
792         CHECK_ALL_INFO(io.ntcreatex.out.size, size);
793         CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
794         CHECK_VAL(io.ntcreatex.out.is_directory, 1);
795         CHECK_VAL(io.ntcreatex.out.size, 0);
796         CHECK_VAL(io.ntcreatex.out.alloc_size, 0);
797         CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
798         smbcli_unlink(cli->tree, fname);
799         
800
801 done:
802         smbcli_close(cli->tree, fnum);
803         smbcli_unlink(cli->tree, fname);
804
805         return ret;
806 }
807
808
809 /*
810   test RAW_OPEN_NTTRANS_CREATE
811 */
812 static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
813 {
814         union smb_open io;
815         union smb_fileinfo finfo;
816         const char *fname = BASEDIR "\\torture_ntcreatex.txt";
817         const char *dname = BASEDIR "\\torture_ntcreatex.dir";
818         NTSTATUS status;
819         int fnum = -1;
820         BOOL ret = True;
821         int i;
822         struct {
823                 uint32_t open_disp;
824                 BOOL with_file;
825                 NTSTATUS correct_status;
826         } open_funcs[] = {
827                 { NTCREATEX_DISP_SUPERSEDE,     True,  NT_STATUS_OK },
828                 { NTCREATEX_DISP_SUPERSEDE,     False, NT_STATUS_OK },
829                 { NTCREATEX_DISP_OPEN,          True,  NT_STATUS_OK },
830                 { NTCREATEX_DISP_OPEN,          False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
831                 { NTCREATEX_DISP_CREATE,        True,  NT_STATUS_OBJECT_NAME_COLLISION },
832                 { NTCREATEX_DISP_CREATE,        False, NT_STATUS_OK },
833                 { NTCREATEX_DISP_OPEN_IF,       True,  NT_STATUS_OK },
834                 { NTCREATEX_DISP_OPEN_IF,       False, NT_STATUS_OK },
835                 { NTCREATEX_DISP_OVERWRITE,     True,  NT_STATUS_OK },
836                 { NTCREATEX_DISP_OVERWRITE,     False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
837                 { NTCREATEX_DISP_OVERWRITE_IF,  True,  NT_STATUS_OK },
838                 { NTCREATEX_DISP_OVERWRITE_IF,  False, NT_STATUS_OK },
839                 { 6,                            True,  NT_STATUS_INVALID_PARAMETER },
840                 { 6,                            False, NT_STATUS_INVALID_PARAMETER },
841         };
842
843         printf("Checking RAW_OPEN_NTTRANS_CREATE\n");
844
845         /* reasonable default parameters */
846         io.generic.level = RAW_OPEN_NTTRANS_CREATE;
847         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
848         io.ntcreatex.in.root_fid = 0;
849         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
850         io.ntcreatex.in.alloc_size = 1024*1024;
851         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
852         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
853         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
854         io.ntcreatex.in.create_options = 0;
855         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
856         io.ntcreatex.in.security_flags = 0;
857         io.ntcreatex.in.fname = fname;
858         io.ntcreatex.in.sec_desc = NULL;
859         io.ntcreatex.in.ea_list = NULL;
860
861         /* test the open disposition */
862         for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
863                 if (open_funcs[i].with_file) {
864                         fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR|O_TRUNC, DENY_NONE);
865                         if (fnum == -1) {
866                                 d_printf("Failed to create file %s - %s\n", fname, smbcli_errstr(cli->tree));
867                                 ret = False;
868                                 goto done;
869                         }
870                         smbcli_close(cli->tree, fnum);
871                 }
872                 io.ntcreatex.in.open_disposition = open_funcs[i].open_disp;
873                 status = smb_raw_open(cli->tree, mem_ctx, &io);
874                 if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
875                         printf("(%s) incorrect status %s should be %s (i=%d with_file=%d open_disp=%d)\n", 
876                                __location__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
877                                i, (int)open_funcs[i].with_file, (int)open_funcs[i].open_disp);
878                         ret = False;
879                 }
880                 if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
881                         smbcli_close(cli->tree, io.ntcreatex.out.fnum);
882                         smbcli_unlink(cli->tree, fname);
883                 }
884         }
885
886         /* basic field testing */
887         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
888
889         status = smb_raw_open(cli->tree, mem_ctx, &io);
890         CHECK_STATUS(status, NT_STATUS_OK);
891         fnum = io.ntcreatex.out.fnum;
892
893         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
894         CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
895         CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
896         CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
897         CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
898         CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
899         CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
900         CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
901         CHECK_ALL_INFO(io.ntcreatex.out.size, size);
902         CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
903         CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
904
905         /* check fields when the file already existed */
906         smbcli_close(cli->tree, fnum);
907         smbcli_unlink(cli->tree, fname);
908         fnum = create_complex_file(cli, mem_ctx, fname);
909         if (fnum == -1) {
910                 ret = False;
911                 goto done;
912         }
913         smbcli_close(cli->tree, fnum);
914
915         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
916         status = smb_raw_open(cli->tree, mem_ctx, &io);
917         CHECK_STATUS(status, NT_STATUS_OK);
918         fnum = io.ntcreatex.out.fnum;
919
920         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
921         CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
922         CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
923         CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
924         CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
925         CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
926         CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
927         CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
928         CHECK_ALL_INFO(io.ntcreatex.out.size, size);
929         CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
930         CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
931         smbcli_close(cli->tree, fnum);
932         smbcli_unlink(cli->tree, fname);
933
934
935         /* create a directory */
936         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
937         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
938         io.ntcreatex.in.alloc_size = 0;
939         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
940         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
941         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
942         io.ntcreatex.in.create_options = 0;
943         io.ntcreatex.in.fname = dname;
944         fname = dname;
945
946         smbcli_rmdir(cli->tree, fname);
947         smbcli_unlink(cli->tree, fname);
948
949         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
950         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
951         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
952         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
953         status = smb_raw_open(cli->tree, mem_ctx, &io);
954         CHECK_STATUS(status, NT_STATUS_OK);
955         fnum = io.ntcreatex.out.fnum;
956
957         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
958         CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
959         CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
960         CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
961         CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
962         CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
963         CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
964         CHECK_VAL(io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, 
965                   FILE_ATTRIBUTE_DIRECTORY);
966         CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
967         CHECK_ALL_INFO(io.ntcreatex.out.size, size);
968         CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
969         CHECK_VAL(io.ntcreatex.out.is_directory, 1);
970         CHECK_VAL(io.ntcreatex.out.size, 0);
971         CHECK_VAL(io.ntcreatex.out.alloc_size, 0);
972         CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
973         smbcli_unlink(cli->tree, fname);
974         
975
976 done:
977         smbcli_close(cli->tree, fnum);
978         smbcli_unlink(cli->tree, fname);
979
980         return ret;
981 }
982
983 /*
984   test RAW_OPEN_NTCREATEX with an already opened and byte range locked file
985
986   I've got an application that does a similar sequence of ntcreate&x,
987   locking&x and another ntcreate&x with
988   open_disposition==NTCREATEX_DISP_OVERWRITE_IF. Windows 2003 allows the
989   second open.
990 */
991 static BOOL test_ntcreatex_brlocked(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
992 {
993         union smb_open io, io1;
994         union smb_lock io2;
995         struct smb_lock_entry lock[1];
996         const char *fname = BASEDIR "\\torture_ntcreatex.txt";
997         NTSTATUS status;
998         BOOL ret = True;
999
1000         printf("Testing ntcreatex with a byte range locked file\n");
1001
1002         io.generic.level = RAW_OPEN_NTCREATEX;
1003         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
1004         io.ntcreatex.in.root_fid = 0;
1005         io.ntcreatex.in.access_mask = 0x2019f;
1006         io.ntcreatex.in.alloc_size = 0;
1007         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1008         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1009                 NTCREATEX_SHARE_ACCESS_WRITE;
1010         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1011         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1012         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
1013         io.ntcreatex.in.security_flags = NTCREATEX_SECURITY_DYNAMIC |
1014                 NTCREATEX_SECURITY_ALL;
1015         io.ntcreatex.in.fname = fname;
1016
1017         status = smb_raw_open(cli->tree, mem_ctx, &io);
1018         CHECK_STATUS(status, NT_STATUS_OK);
1019
1020         io2.lockx.level = RAW_LOCK_LOCKX;
1021         io2.lockx.in.fnum = io.ntcreatex.out.fnum;
1022         io2.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1023         io2.lockx.in.timeout = 0;
1024         io2.lockx.in.ulock_cnt = 0;
1025         io2.lockx.in.lock_cnt = 1;
1026         lock[0].pid = cli->session->pid;
1027         lock[0].offset = 0;
1028         lock[0].count = 0x1;
1029         io2.lockx.in.locks = &lock[0];
1030         status = smb_raw_lock(cli->tree, &io2);
1031         CHECK_STATUS(status, NT_STATUS_OK);
1032
1033         io1.generic.level = RAW_OPEN_NTCREATEX;
1034         io1.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
1035         io1.ntcreatex.in.root_fid = 0;
1036         io1.ntcreatex.in.access_mask = 0x20196;
1037         io1.ntcreatex.in.alloc_size = 0;
1038         io1.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1039         io1.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1040                 NTCREATEX_SHARE_ACCESS_WRITE;
1041         io1.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1042         io1.ntcreatex.in.create_options = 0;
1043         io1.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
1044         io1.ntcreatex.in.security_flags = NTCREATEX_SECURITY_DYNAMIC |
1045                 NTCREATEX_SECURITY_ALL;
1046         io1.ntcreatex.in.fname = fname;
1047
1048         status = smb_raw_open(cli->tree, mem_ctx, &io1);
1049         CHECK_STATUS(status, NT_STATUS_OK);
1050
1051  done:
1052         smbcli_close(cli->tree, io.ntcreatex.out.fnum);
1053         smbcli_close(cli->tree, io1.ntcreatex.out.fnum);
1054         smbcli_unlink(cli->tree, fname);
1055         return ret;
1056 }
1057
1058 /*
1059   test RAW_OPEN_MKNEW
1060 */
1061 static BOOL test_mknew(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1062 {
1063         union smb_open io;
1064         const char *fname = BASEDIR "\\torture_mknew.txt";
1065         NTSTATUS status;
1066         int fnum = -1;
1067         BOOL ret = True;
1068         time_t basetime = (time(NULL) + 3600*24*3) & ~1;
1069         union smb_fileinfo finfo;
1070
1071         printf("Checking RAW_OPEN_MKNEW\n");
1072
1073         io.mknew.level = RAW_OPEN_MKNEW;
1074         io.mknew.in.attrib = 0;
1075         io.mknew.in.write_time = 0;
1076         io.mknew.in.fname = fname;
1077         status = smb_raw_open(cli->tree, mem_ctx, &io);
1078         CHECK_STATUS(status, NT_STATUS_OK);
1079         fnum = io.mknew.out.fnum;
1080
1081         status = smb_raw_open(cli->tree, mem_ctx, &io);
1082         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1083
1084         smbcli_close(cli->tree, fnum);
1085         smbcli_unlink(cli->tree, fname);
1086
1087         /* make sure write_time works */
1088         io.mknew.in.write_time = basetime;
1089         status = smb_raw_open(cli->tree, mem_ctx, &io);
1090         CHECK_STATUS(status, NT_STATUS_OK);
1091         fnum = io.mknew.out.fnum;
1092         CHECK_TIME(basetime, write_time);
1093
1094         smbcli_close(cli->tree, fnum);
1095         smbcli_unlink(cli->tree, fname);
1096
1097         /* make sure file_attrs works */
1098         io.mknew.in.attrib = FILE_ATTRIBUTE_HIDDEN;
1099         status = smb_raw_open(cli->tree, mem_ctx, &io);
1100         CHECK_STATUS(status, NT_STATUS_OK);
1101         fnum = io.mknew.out.fnum;
1102         CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE, 
1103                        attrib & ~FILE_ATTRIBUTE_NONINDEXED);
1104         
1105 done:
1106         smbcli_close(cli->tree, fnum);
1107         smbcli_unlink(cli->tree, fname);
1108
1109         return ret;
1110 }
1111
1112
1113 /*
1114   test RAW_OPEN_CREATE
1115 */
1116 static BOOL test_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1117 {
1118         union smb_open io;
1119         const char *fname = BASEDIR "\\torture_create.txt";
1120         NTSTATUS status;
1121         int fnum = -1;
1122         BOOL ret = True;
1123         time_t basetime = (time(NULL) + 3600*24*3) & ~1;
1124         union smb_fileinfo finfo;
1125
1126         printf("Checking RAW_OPEN_CREATE\n");
1127
1128         io.create.level = RAW_OPEN_CREATE;
1129         io.create.in.attrib = 0;
1130         io.create.in.write_time = 0;
1131         io.create.in.fname = fname;
1132         status = smb_raw_open(cli->tree, mem_ctx, &io);
1133         CHECK_STATUS(status, NT_STATUS_OK);
1134         fnum = io.create.out.fnum;
1135
1136         status = smb_raw_open(cli->tree, mem_ctx, &io);
1137         CHECK_STATUS(status, NT_STATUS_OK);
1138
1139         smbcli_close(cli->tree, io.create.out.fnum);
1140         smbcli_close(cli->tree, fnum);
1141         smbcli_unlink(cli->tree, fname);
1142
1143         /* make sure write_time works */
1144         io.create.in.write_time = basetime;
1145         status = smb_raw_open(cli->tree, mem_ctx, &io);
1146         CHECK_STATUS(status, NT_STATUS_OK);
1147         fnum = io.create.out.fnum;
1148         CHECK_TIME(basetime, write_time);
1149
1150         smbcli_close(cli->tree, fnum);
1151         smbcli_unlink(cli->tree, fname);
1152
1153         /* make sure file_attrs works */
1154         io.create.in.attrib = FILE_ATTRIBUTE_HIDDEN;
1155         status = smb_raw_open(cli->tree, mem_ctx, &io);
1156         CHECK_STATUS(status, NT_STATUS_OK);
1157         fnum = io.create.out.fnum;
1158         CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE, 
1159                        attrib & ~FILE_ATTRIBUTE_NONINDEXED);
1160         
1161 done:
1162         smbcli_close(cli->tree, fnum);
1163         smbcli_unlink(cli->tree, fname);
1164
1165         return ret;
1166 }
1167
1168
1169 /*
1170   test RAW_OPEN_CTEMP
1171 */
1172 static BOOL test_ctemp(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1173 {
1174         union smb_open io;
1175         NTSTATUS status;
1176         int fnum = -1;
1177         BOOL ret = True;
1178         time_t basetime = (time(NULL) + 3600*24*3) & ~1;
1179         union smb_fileinfo finfo;
1180         const char *name, *fname = NULL;
1181
1182         printf("Checking RAW_OPEN_CTEMP\n");
1183
1184         io.ctemp.level = RAW_OPEN_CTEMP;
1185         io.ctemp.in.attrib = FILE_ATTRIBUTE_HIDDEN;
1186         io.ctemp.in.write_time = basetime;
1187         io.ctemp.in.directory = BASEDIR;
1188         status = smb_raw_open(cli->tree, mem_ctx, &io);
1189         CHECK_STATUS(status, NT_STATUS_OK);
1190         fnum = io.ctemp.out.fnum;
1191
1192         name = io.ctemp.out.name;
1193
1194         finfo.generic.level = RAW_FILEINFO_NAME_INFO;
1195         finfo.generic.in.fnum = fnum;
1196         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
1197         CHECK_STATUS(status, NT_STATUS_OK);
1198
1199         fname = finfo.name_info.out.fname.s;
1200         d_printf("ctemp name=%s  real name=%s\n", name, fname);
1201
1202 done:
1203         smbcli_close(cli->tree, fnum);
1204         if (fname) {
1205                 smbcli_unlink(cli->tree, fname);
1206         }
1207
1208         return ret;
1209 }
1210
1211
1212 /*
1213   test chained RAW_OPEN_OPENX_READX
1214 */
1215 static BOOL test_chained(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1216 {
1217         union smb_open io;
1218         const char *fname = BASEDIR "\\torture_chained.txt";
1219         NTSTATUS status;
1220         int fnum = -1;
1221         BOOL ret = True;
1222         const char *buf = "test";
1223         char buf2[4];
1224
1225         printf("Checking RAW_OPEN_OPENX chained with READX\n");
1226         smbcli_unlink(cli->tree, fname);
1227
1228         fnum = create_complex_file(cli, mem_ctx, fname);
1229
1230         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
1231
1232         smbcli_close(cli->tree, fnum);  
1233
1234         io.openxreadx.level = RAW_OPEN_OPENX_READX;
1235         io.openxreadx.in.fname = fname;
1236         io.openxreadx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1237         io.openxreadx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
1238         io.openxreadx.in.open_func = OPENX_OPEN_FUNC_OPEN;
1239         io.openxreadx.in.search_attrs = 0;
1240         io.openxreadx.in.file_attrs = 0;
1241         io.openxreadx.in.write_time = 0;
1242         io.openxreadx.in.size = 1024*1024;
1243         io.openxreadx.in.timeout = 0;
1244         
1245         io.openxreadx.in.offset = 0;
1246         io.openxreadx.in.mincnt = sizeof(buf);
1247         io.openxreadx.in.maxcnt = sizeof(buf);
1248         io.openxreadx.in.remaining = 0;
1249         io.openxreadx.out.data = buf2;
1250
1251         status = smb_raw_open(cli->tree, mem_ctx, &io);
1252         CHECK_STATUS(status, NT_STATUS_OK);
1253         fnum = io.openxreadx.out.fnum;
1254
1255         if (memcmp(buf, buf2, sizeof(buf)) != 0) {
1256                 d_printf("wrong data in reply buffer\n");
1257                 ret = False;
1258         }
1259
1260 done:
1261         smbcli_close(cli->tree, fnum);
1262         smbcli_unlink(cli->tree, fname);
1263
1264         return ret;
1265 }
1266
1267 /* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
1268
1269 static BOOL test_raw_open_multi(void)
1270 {
1271         struct smbcli_state *cli;
1272         TALLOC_CTX *mem_ctx = talloc_init("torture_test_oplock_multi");
1273         const char *fname = "\\test_oplock.dat";
1274         NTSTATUS status;
1275         BOOL ret = True;
1276         union smb_open io;
1277         struct smbcli_state **clients;
1278         struct smbcli_request **requests;
1279         union smb_open *ios;
1280         const char *host = lp_parm_string(-1, "torture", "host");
1281         const char *share = lp_parm_string(-1, "torture", "share");
1282         int i, num_files = 3;
1283         struct event_context *ev;
1284         int num_ok = 0;
1285         int num_collision = 0;
1286         
1287         ev = event_context_init(mem_ctx);
1288         clients = talloc_array(mem_ctx, struct smbcli_state *, num_files);
1289         requests = talloc_array(mem_ctx, struct smbcli_request *, num_files);
1290         ios = talloc_array(mem_ctx, union smb_open, num_files);
1291         if ((ev == NULL) || (clients == NULL) || (requests == NULL) ||
1292             (ios == NULL)) {
1293                 DEBUG(0, ("talloc failed\n"));
1294                 return False;
1295         }
1296
1297         if (!torture_open_connection_share(mem_ctx, &cli, host, share, ev)) {
1298                 return False;
1299         }
1300
1301         cli->tree->session->transport->options.request_timeout = 60000;
1302
1303         for (i=0; i<num_files; i++) {
1304                 if (!torture_open_connection_share(mem_ctx, &(clients[i]),
1305                                                    host, share, ev)) {
1306                         DEBUG(0, ("Could not open %d'th connection\n", i));
1307                         return False;
1308                 }
1309                 clients[i]->tree->session->transport->
1310                         options.request_timeout = 60000;
1311         }
1312
1313         /* cleanup */
1314         smbcli_unlink(cli->tree, fname);
1315
1316         /*
1317           base ntcreatex parms
1318         */
1319         io.generic.level = RAW_OPEN_NTCREATEX;
1320         io.ntcreatex.in.root_fid = 0;
1321         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
1322         io.ntcreatex.in.alloc_size = 0;
1323         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1324         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1325                 NTCREATEX_SHARE_ACCESS_WRITE|
1326                 NTCREATEX_SHARE_ACCESS_DELETE;
1327         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1328         io.ntcreatex.in.create_options = 0;
1329         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1330         io.ntcreatex.in.security_flags = 0;
1331         io.ntcreatex.in.fname = fname;
1332         io.ntcreatex.in.flags = 0;
1333
1334         for (i=0; i<num_files; i++) {
1335                 ios[i] = io;
1336                 requests[i] = smb_raw_open_send(clients[i]->tree, &ios[i]);
1337                 if (requests[i] == NULL) {
1338                         DEBUG(0, ("could not send %d'th request\n", i));
1339                         return False;
1340                 }
1341         }
1342
1343         DEBUG(10, ("waiting for replies\n"));
1344         while (1) {
1345                 BOOL unreplied = False;
1346                 for (i=0; i<num_files; i++) {
1347                         if (requests[i] == NULL) {
1348                                 continue;
1349                         }
1350                         if (requests[i]->state < SMBCLI_REQUEST_DONE) {
1351                                 unreplied = True;
1352                                 break;
1353                         }
1354                         status = smb_raw_open_recv(requests[i], mem_ctx,
1355                                                    &ios[i]);
1356
1357                         DEBUG(0, ("File %d returned status %s\n", i,
1358                                   nt_errstr(status)));
1359
1360                         if (NT_STATUS_IS_OK(status)) {
1361                                 num_ok += 1;
1362                         } 
1363
1364                         if (NT_STATUS_EQUAL(status,
1365                                             NT_STATUS_OBJECT_NAME_COLLISION)) {
1366                                 num_collision += 1;
1367                         }
1368
1369                         requests[i] = NULL;
1370                 }
1371                 if (!unreplied) {
1372                         break;
1373                 }
1374
1375                 if (event_loop_once(ev) != 0) {
1376                         DEBUG(0, ("event_loop_once failed\n"));
1377                         return False;
1378                 }
1379         }
1380
1381         if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
1382                 ret = False;
1383         }
1384
1385         for (i=0; i<num_files; i++) {
1386                 torture_close_connection(clients[i]);
1387         }
1388         talloc_free(mem_ctx);
1389         return ret;
1390 }
1391
1392 /* basic testing of all RAW_OPEN_* calls 
1393 */
1394 BOOL torture_raw_open(void)
1395 {
1396         struct smbcli_state *cli;
1397         BOOL ret = True;
1398         TALLOC_CTX *mem_ctx;
1399
1400         if (!torture_open_connection(&cli)) {
1401                 return False;
1402         }
1403
1404         mem_ctx = talloc_init("torture_raw_open");
1405
1406         if (!torture_setup_dir(cli, BASEDIR)) {
1407                 return False;
1408         }
1409
1410         ret &= test_ntcreatex_brlocked(cli, mem_ctx);
1411         ret &= test_open(cli, mem_ctx);
1412         ret &= test_raw_open_multi();
1413         ret &= test_openx(cli, mem_ctx);
1414         ret &= test_ntcreatex(cli, mem_ctx);
1415         ret &= test_nttrans_create(cli, mem_ctx);
1416         ret &= test_t2open(cli, mem_ctx);
1417         ret &= test_mknew(cli, mem_ctx);
1418         ret &= test_create(cli, mem_ctx);
1419         ret &= test_ctemp(cli, mem_ctx);
1420         ret &= test_chained(cli, mem_ctx);
1421
1422         smb_raw_exit(cli->session);
1423         smbcli_deltree(cli->tree, BASEDIR);
1424
1425         torture_close_connection(cli);
1426         talloc_free(mem_ctx);
1427         return ret;
1428 }