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