first public release of samba4 code
[jelmer/samba4-debian.git] / source / torture / qfileinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3    RAW_FILEINFO_* 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
23 static struct {
24         const char *name;
25         enum fileinfo_level level;
26         unsigned only_paths:1;
27         unsigned only_handles:1;
28         NTSTATUS fnum_status, fname_status;
29         union smb_fileinfo fnum_finfo, fname_finfo;
30 } levels[] = {
31         { "GETATTR",                   RAW_FILEINFO_GETATTR,           1, 0, },
32         { "GETATTRE",                  RAW_FILEINFO_GETATTRE,          0, 1, },
33         { "STANDARD",                  RAW_FILEINFO_STANDARD, },
34         { "EA_SIZE",                   RAW_FILEINFO_EA_SIZE, },
35         { "ALL_EAS",                   RAW_FILEINFO_ALL_EAS, },
36         { "IS_NAME_VALID",             RAW_FILEINFO_IS_NAME_VALID,     1, 0, },
37         { "BASIC_INFO",                RAW_FILEINFO_BASIC_INFO, },
38         { "STANDARD_INFO",             RAW_FILEINFO_STANDARD_INFO, },
39         { "EA_INFO",                   RAW_FILEINFO_EA_INFO, },
40         { "NAME_INFO",                 RAW_FILEINFO_NAME_INFO, },
41         { "ALL_INFO",                  RAW_FILEINFO_ALL_INFO, },
42         { "ALT_NAME_INFO",             RAW_FILEINFO_ALT_NAME_INFO, },
43         { "STREAM_INFO",               RAW_FILEINFO_STREAM_INFO, },
44         { "COMPRESSION_INFO",          RAW_FILEINFO_COMPRESSION_INFO, },
45         { "BASIC_INFORMATION",         RAW_FILEINFO_BASIC_INFORMATION, },
46         { "STANDARD_INFORMATION",      RAW_FILEINFO_STANDARD_INFORMATION, },
47         { "INTERNAL_INFORMATION",      RAW_FILEINFO_INTERNAL_INFORMATION, },
48         { "EA_INFORMATION",            RAW_FILEINFO_EA_INFORMATION, },
49         { "ACCESS_INFORMATION",        RAW_FILEINFO_ACCESS_INFORMATION, },
50         { "NAME_INFORMATION",          RAW_FILEINFO_NAME_INFORMATION, },
51         { "POSITION_INFORMATION",      RAW_FILEINFO_POSITION_INFORMATION, },
52         { "MODE_INFORMATION",          RAW_FILEINFO_MODE_INFORMATION, },
53         { "ALIGNMENT_INFORMATION",     RAW_FILEINFO_ALIGNMENT_INFORMATION, },
54         { "ALL_INFORMATION",           RAW_FILEINFO_ALL_INFORMATION, },
55         { "ALT_NAME_INFORMATION",      RAW_FILEINFO_ALT_NAME_INFORMATION, },
56         { "STREAM_INFORMATION",        RAW_FILEINFO_STREAM_INFORMATION, },
57         { "COMPRESSION_INFORMATION",   RAW_FILEINFO_COMPRESSION_INFORMATION, },
58         { "NETWORK_OPEN_INFORMATION",  RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
59         { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
60         { NULL, }
61 };
62
63 /*
64   compare a dos time (2 second resolution) to a nt time
65 */
66 static int dos_nt_time_cmp(time_t t, const NTTIME *nt)
67 {
68         time_t t2 = nt_time_to_unix(nt);
69         if (ABS(t2 - t) <= 2) return 0;
70         return t2 - t;
71 }
72
73
74 /*
75   find a level in the levels[] table
76 */
77 static union smb_fileinfo *fnum_find(const char *name)
78 {
79         int i;
80         for (i=0; levels[i].name; i++) {
81                 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
82                     strcmp(name, levels[i].name) == 0 && 
83                     !levels[i].only_paths) {
84                         return &levels[i].fnum_finfo;
85                 }
86         }
87         return NULL;
88 }
89
90 /*
91   find a level in the levels[] table
92 */
93 static union smb_fileinfo *fname_find(const char *name)
94 {
95         int i;
96         for (i=0; levels[i].name; i++) {
97                 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
98                     strcmp(name, levels[i].name) == 0 && 
99                     !levels[i].only_handles) {
100                         return &levels[i].fname_finfo;
101                 }
102         }
103         return NULL;
104 }
105
106 /* local macros to make the code below more readable */
107 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
108         printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
109                #n1, #v1, (uint_t)s1->n1.out.v1, \
110                #n2, #v2, (uint_t)s2->n2.out.v2, \
111                __FILE__, __LINE__); \
112         ret = False; \
113 }} while(0)
114
115 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
116                                           s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
117         printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
118                #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
119                #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
120                __FILE__, __LINE__); \
121         ret = False; \
122 }} while(0)
123
124 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
125         printf("%s/%s != %s/%s at %s(%d)\n", \
126                #n1, #v1, \
127                #n2, #v2, \
128                __FILE__, __LINE__); \
129         ret = False; \
130 }} while(0)
131
132 /* used to find hints on unknown values - and to make sure 
133    we zero-fill */
134 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
135         printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
136                #n1, #v1, \
137                (uint_t)s1->n1.out.v1, \
138                (uint_t)s1->n1.out.v1, \
139                __FILE__, __LINE__); \
140         ret = False; \
141 }} while(0)
142
143 /* basic testing of all RAW_FILEINFO_* calls 
144    for each call we test that it succeeds, and where possible test 
145    for consistency between the calls. 
146 */
147 BOOL torture_qfileinfo(int dummy)
148 {
149         struct cli_state *cli;
150         int i;
151         BOOL ret = True;
152         int count;
153         union smb_fileinfo *s1, *s2;    
154         TALLOC_CTX *mem_ctx;
155         int fnum;
156         const char *fname = "\\torture_qfileinfo.txt";
157         NTTIME correct_time;
158         large_t correct_size;
159         uint32 correct_attrib;
160         const char *correct_name;
161         BOOL skip_streams = False;
162
163         if (!torture_open_connection(&cli)) {
164                 return False;
165         }
166
167         mem_ctx = talloc_init("torture_qfileinfo");
168
169         fnum = create_complex_file(cli, mem_ctx, fname);
170         if (fnum == -1) {
171                 printf("ERROR: open of %s failed (%s)\n", fname, cli_errstr(cli));
172                 ret = False;
173                 goto done;
174         }
175         
176         
177         /* scan all the fileinfo and pathinfo levels */
178         for (i=0; levels[i].name; i++) {
179                 if (!levels[i].only_paths) {
180                         levels[i].fnum_finfo.generic.level = levels[i].level;
181                         levels[i].fnum_finfo.generic.in.fnum = fnum;
182                         levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx, 
183                                                                  &levels[i].fnum_finfo);
184                 }
185
186                 if (!levels[i].only_handles) {
187                         levels[i].fname_finfo.generic.level = levels[i].level;
188                         levels[i].fname_finfo.generic.in.fname = talloc_strdup(mem_ctx, fname);
189                         levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx, 
190                                                                   &levels[i].fname_finfo);
191                 }
192         }
193
194         /* check for completely broken levels */
195         for (count=i=0; levels[i].name; i++) {
196                 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
197                         printf("ERROR: level %s failed - %s\n", 
198                                levels[i].name, nt_errstr(levels[i].fnum_status));
199                         count++;
200                 }
201                 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
202                         printf("ERROR: level %s failed - %s\n", 
203                                levels[i].name, nt_errstr(levels[i].fname_status));
204                         count++;
205                 }
206         }
207
208         if (count != 0) {
209                 ret = False;
210                 printf("%d levels failed\n", count);
211                 if (count > 32) {
212                         printf("too many level failures - giving up\n");
213                         goto done;
214                 }
215         }
216
217         /* see if we can do streams */
218         s1 = fnum_find("STREAM_INFO");
219         if (!s1 || s1->stream_info.out.num_streams == 0) {
220                 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
221                        s1 ? s1->stream_info.out.num_streams : -1);
222                 skip_streams = True;
223         }       
224
225
226         /* this code is incredibly repititive but doesn't lend itself to loops, so
227            we use lots of macros to make it less painful */
228
229         /* first off we check the levels that are supposed to be aliases. It will be quite rare for 
230            this code to fail, but we need to check it for completeness */
231
232
233
234 #define ALIAS_CHECK(sname1, sname2) \
235         do { \
236                 s1 = fnum_find(sname1);  s2 = fnum_find(sname2); \
237                 if (s1 && s2) { INFO_CHECK } \
238                 s1 = fname_find(sname1); s2 = fname_find(sname2); \
239                 if (s1 && s2) { INFO_CHECK } \
240                 s1 = fnum_find(sname1);  s2 = fname_find(sname2); \
241                 if (s1 && s2) { INFO_CHECK } \
242         } while (0)
243
244 #define INFO_CHECK \
245                 STRUCT_EQUAL(basic_info,  create_time, basic_info, create_time); \
246                 STRUCT_EQUAL(basic_info,  access_time, basic_info, access_time); \
247                 STRUCT_EQUAL(basic_info,  write_time,  basic_info, write_time); \
248                 STRUCT_EQUAL(basic_info,  change_time, basic_info, change_time); \
249                 VAL_EQUAL   (basic_info,  attrib,      basic_info, attrib);
250
251         ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
252
253 #undef INFO_CHECK
254 #define INFO_CHECK \
255                 VAL_EQUAL(standard_info,  alloc_size,     standard_info, alloc_size); \
256                 VAL_EQUAL(standard_info,  size,           standard_info, size); \
257                 VAL_EQUAL(standard_info,  nlink,          standard_info, nlink); \
258                 VAL_EQUAL(standard_info,  delete_pending, standard_info, delete_pending); \
259                 VAL_EQUAL(standard_info,  directory,      standard_info, directory);
260
261         ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
262
263 #undef INFO_CHECK
264 #define INFO_CHECK \
265                 VAL_EQUAL(ea_info,  ea_size,     ea_info, ea_size);
266
267         ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
268
269 #undef INFO_CHECK
270 #define INFO_CHECK \
271                 STR_EQUAL(name_info,  fname,   name_info, fname);
272
273         ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
274
275 #undef INFO_CHECK
276 #define INFO_CHECK \
277                 STRUCT_EQUAL(all_info,  create_time,           all_info, create_time); \
278                 STRUCT_EQUAL(all_info,  access_time,           all_info, access_time); \
279                 STRUCT_EQUAL(all_info,  write_time,            all_info, write_time); \
280                 STRUCT_EQUAL(all_info,  change_time,           all_info, change_time); \
281                    VAL_EQUAL(all_info,  attrib,                all_info, attrib); \
282                    VAL_EQUAL(all_info,  alloc_size,            all_info, alloc_size); \
283                    VAL_EQUAL(all_info,  size,                  all_info, size); \
284                    VAL_EQUAL(all_info,  nlink,                 all_info, nlink); \
285                    VAL_EQUAL(all_info,  delete_pending,        all_info, delete_pending); \
286                    VAL_EQUAL(all_info,  directory,             all_info, directory); \
287                    VAL_EQUAL(all_info,  ea_size,               all_info, ea_size); \
288                    STR_EQUAL(all_info,  fname,                 all_info, fname);
289
290         ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
291
292
293 #undef INFO_CHECK
294 #define INFO_CHECK \
295                 STR_EQUAL(alt_name_info,  fname,   alt_name_info, fname);
296
297         ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
298
299 #define TIME_CHECK_NT(sname, stype, tfield) do { \
300         s1 = fnum_find(sname); \
301         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
302                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
303                        nt_time_string(mem_ctx, &s1->stype.out.tfield), \
304                        nt_time_string(mem_ctx, &correct_time)); \
305                 ret = False; \
306         } \
307         s1 = fname_find(sname); \
308         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
309                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
310                        nt_time_string(mem_ctx, &s1->stype.out.tfield), \
311                        nt_time_string(mem_ctx, &correct_time)); \
312                 ret = False; \
313         }} while (0)
314
315 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
316         s1 = fnum_find(sname); \
317         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
318                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
319                        time_string(mem_ctx, s1->stype.out.tfield), \
320                        nt_time_string(mem_ctx, &correct_time)); \
321                 ret = False; \
322         } \
323         s1 = fname_find(sname); \
324         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
325                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
326                        time_string(mem_ctx, s1->stype.out.tfield), \
327                        nt_time_string(mem_ctx, &correct_time)); \
328                 ret = False; \
329         }} while (0)
330
331 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
332         s1 = fnum_find(sname); \
333         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
334                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
335                        time_string(mem_ctx, s1->stype.out.tfield), \
336                        nt_time_string(mem_ctx, &correct_time)); \
337                 ret = False; \
338         } \
339         s1 = fname_find(sname); \
340         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
341                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
342                        time_string(mem_ctx, s1->stype.out.tfield), \
343                        nt_time_string(mem_ctx, &correct_time)); \
344                 ret = False; \
345         }} while (0)
346
347         /* now check that all the times that are supposed to be equal are correct */
348         s1 = fnum_find("BASIC_INFO");
349         correct_time = s1->basic_info.out.create_time;
350         printf("create_time: %s\n", nt_time_string(mem_ctx, &correct_time));
351
352         TIME_CHECK_NT ("BASIC_INFO",               basic_info, create_time);
353         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, create_time);
354         TIME_CHECK_DOS("GETATTRE",                 getattre,   create_time);
355         TIME_CHECK_DOS("STANDARD",                 standard,   create_time);
356         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    create_time);
357         TIME_CHECK_NT ("ALL_INFO",                 all_info,   create_time);
358         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
359
360         s1 = fnum_find("BASIC_INFO");
361         correct_time = s1->basic_info.out.access_time;
362         printf("access_time: %s\n", nt_time_string(mem_ctx, &correct_time));
363
364         TIME_CHECK_NT ("BASIC_INFO",               basic_info, access_time);
365         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, access_time);
366         TIME_CHECK_DOS("GETATTRE",                 getattre,   access_time);
367         TIME_CHECK_DOS("STANDARD",                 standard,   access_time);
368         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    access_time);
369         TIME_CHECK_NT ("ALL_INFO",                 all_info,   access_time);
370         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
371
372         s1 = fnum_find("BASIC_INFO");
373         correct_time = s1->basic_info.out.write_time;
374         printf("write_time : %s\n", nt_time_string(mem_ctx, &correct_time));
375
376         TIME_CHECK_NT ("BASIC_INFO",               basic_info, write_time);
377         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, write_time);
378         TIME_CHECK_DOS("GETATTRE",                 getattre,   write_time);
379         TIME_CHECK_DOS("STANDARD",                 standard,   write_time);
380         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    write_time);
381         TIME_CHECK_NT ("ALL_INFO",                 all_info,   write_time);
382         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
383
384         s1 = fnum_find("BASIC_INFO");
385         correct_time = s1->basic_info.out.change_time;
386         printf("change_time: %s\n", nt_time_string(mem_ctx, &correct_time));
387
388         TIME_CHECK_NT ("BASIC_INFO",               basic_info, change_time);
389         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, change_time);
390         TIME_CHECK_NT ("ALL_INFO",                 all_info,   change_time);
391         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
392
393
394 #define SIZE_CHECK(sname, stype, tfield) do { \
395         s1 = fnum_find(sname); \
396         if (s1 && s1->stype.out.tfield != correct_size) { \
397                 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
398                        (unsigned)s1->stype.out.tfield, \
399                        (unsigned)correct_size); \
400                 ret = False; \
401         } \
402         s1 = fname_find(sname); \
403         if (s1 && s1->stype.out.tfield != correct_size) { \
404                 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
405                        (unsigned)s1->stype.out.tfield, \
406                        (unsigned)correct_size); \
407                 ret = False; \
408         }} while (0)
409
410         s1 = fnum_find("STANDARD_INFO");
411         correct_size = s1->standard_info.out.size;
412         printf("size: %u\n", (unsigned)correct_size);
413         
414         SIZE_CHECK("GETATTR",                  getattr,                  size);
415         SIZE_CHECK("GETATTRE",                 getattre,                 size);
416         SIZE_CHECK("STANDARD",                 standard,                 size);
417         SIZE_CHECK("EA_SIZE",                  ea_size,                  size);
418         SIZE_CHECK("STANDARD_INFO",            standard_info,            size);
419         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            size);
420         SIZE_CHECK("ALL_INFO",                 all_info,                 size);
421         SIZE_CHECK("ALL_INFORMATION",          all_info,                 size);
422         SIZE_CHECK("COMPRESSION_INFO",         compression_info,         compressed_size);
423         SIZE_CHECK("COMPRESSION_INFORMATION",  compression_info,         compressed_size);
424         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
425         if (!skip_streams) {
426                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].size);
427                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].size);
428         }
429
430
431         s1 = fnum_find("STANDARD_INFO");
432         correct_size = s1->standard_info.out.alloc_size;
433         printf("alloc_size: %u\n", (unsigned)correct_size);
434         
435         SIZE_CHECK("GETATTRE",                 getattre,                 alloc_size);
436         SIZE_CHECK("STANDARD",                 standard,                 alloc_size);
437         SIZE_CHECK("EA_SIZE",                  ea_size,                  alloc_size);
438         SIZE_CHECK("STANDARD_INFO",            standard_info,            alloc_size);
439         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            alloc_size);
440         SIZE_CHECK("ALL_INFO",                 all_info,                 alloc_size);
441         SIZE_CHECK("ALL_INFORMATION",          all_info,                 alloc_size);
442         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
443         if (!skip_streams) {
444                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].alloc_size);
445                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].alloc_size);
446         }
447
448 #define ATTRIB_CHECK(sname, stype, tfield) do { \
449         s1 = fnum_find(sname); \
450         if (s1 && s1->stype.out.tfield != correct_attrib) { \
451                 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
452                        (unsigned)s1->stype.out.tfield, \
453                        (unsigned)correct_attrib); \
454                 ret = False; \
455         } \
456         s1 = fname_find(sname); \
457         if (s1 && s1->stype.out.tfield != correct_attrib) { \
458                 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
459                        (unsigned)s1->stype.out.tfield, \
460                        (unsigned)correct_attrib); \
461                 ret = False; \
462         }} while (0)
463
464         s1 = fnum_find("BASIC_INFO");
465         correct_attrib = s1->basic_info.out.attrib;
466         printf("attrib: 0x%x\n", (unsigned)correct_attrib);
467         
468         ATTRIB_CHECK("GETATTR",                   getattr,                   attrib);
469         ATTRIB_CHECK("GETATTRE",                  getattre,                  attrib);
470         ATTRIB_CHECK("STANDARD",                  standard,                  attrib);
471         ATTRIB_CHECK("BASIC_INFO",                basic_info,                attrib);
472         ATTRIB_CHECK("BASIC_INFORMATION",         basic_info,                attrib);
473         ATTRIB_CHECK("EA_SIZE",                   ea_size,                   attrib);
474         ATTRIB_CHECK("ALL_INFO",                  all_info,                  attrib);
475         ATTRIB_CHECK("ALL_INFORMATION",           all_info,                  attrib);
476         ATTRIB_CHECK("NETWORK_OPEN_INFORMATION",  network_open_information,  attrib);
477         ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
478
479         correct_name = fname;
480         printf("name: %s\n", correct_name);
481
482 #define NAME_CHECK(sname, stype, tfield, flags) do { \
483         s1 = fnum_find(sname); \
484         if ((s1 && strcmp(s1->stype.out.tfield.s, correct_name) != 0) || \
485                         wire_bad_flags(&s1->stype.out.tfield, flags)) { \
486                 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
487                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
488                 ret = False; \
489         } \
490         s1 = fname_find(sname); \
491         if ((s1 && strcmp(s1->stype.out.tfield.s, correct_name)) != 0 || \
492                         wire_bad_flags(&s1->stype.out.tfield, flags)) { \
493                 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
494                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
495                 ret = False; \
496         }} while (0)
497
498         NAME_CHECK("NAME_INFO",        name_info, fname, STR_UNICODE);
499         NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
500
501         /* the ALL_INFO file name is the full path on the filesystem */
502         s1 = fnum_find("ALL_INFO");
503         if (s1 && !s1->all_info.out.fname.s) {
504                 printf("ALL_INFO didn't give a filename\n");
505                 ret = False;
506         }
507         if (s1 && s1->all_info.out.fname.s) {
508                 char *p = strrchr(s1->all_info.out.fname.s, '\\');
509                 if (!p) {
510                         printf("Not a full path in all_info/fname? - '%s'\n", 
511                                s1->all_info.out.fname.s);
512                         ret = False;
513                 } else {
514                         if (strcmp(correct_name, p) != 0) {
515                                 printf("incorrect basename in all_info/fname - '%s'\n",
516                                        s1->all_info.out.fname.s);
517                                 ret = False;
518                         }
519                 }
520                 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE)) {
521                         printf("Should not null terminate all_info/fname\n");
522                         ret = False;
523                 }
524         }
525
526         s1 = fnum_find("ALT_NAME_INFO");
527         correct_name = s1->alt_name_info.out.fname.s;
528         printf("alt_name: %s\n", correct_name);
529
530         NAME_CHECK("ALT_NAME_INFO",        alt_name_info, fname, STR_UNICODE);
531         NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
532
533         /* and make sure we can open by alternate name */
534         cli_close(cli, fnum);
535         fnum = cli_nt_create_full(cli, correct_name, 0, NT_ACCESS_GENERIC_ALL_ACCESS, 
536                                   FILE_ATTRIBUTE_NORMAL,
537                                   NTCREATEX_SHARE_ACCESS_DELETE|
538                                   NTCREATEX_SHARE_ACCESS_READ|
539                                   NTCREATEX_SHARE_ACCESS_WRITE, 
540                                   FILE_OVERWRITE_IF, 
541                                   0, 0);
542         if (fnum == -1) {
543                 printf("Unable to open by alt_name - %s\n", cli_errstr(cli));
544                 ret = False;
545         }
546
547         if (!skip_streams) {
548                 correct_name = "::$DATA";
549                 printf("stream_name: %s\n", correct_name);
550
551                 NAME_CHECK("STREAM_INFO",        stream_info, streams[0].stream_name, STR_UNICODE);
552                 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
553         }
554
555         /* make sure the EAs look right */
556         s1 = fnum_find("ALL_EAS");
557         if (s1) {
558                 printf("ea_size: %d\n", s1->all_eas.out.ea_size);
559                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
560                         printf("  flags=%d %s=%*.*s\n", 
561                                s1->all_eas.out.eas[i].flags,
562                                s1->all_eas.out.eas[i].name.s,
563                                s1->all_eas.out.eas[i].value.length,
564                                s1->all_eas.out.eas[i].value.length,
565                                s1->all_eas.out.eas[i].value.data);
566                 }
567         }
568
569
570 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
571         s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
572         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
573                 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
574                        #stype1, #tfield1, #stype2, #tfield2,  \
575                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
576                 ret = False; \
577         } \
578         s1 = fname_find(sname1); s2 = fname_find(sname2); \
579         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
580                 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
581                        #stype1, #tfield1, #stype2, #tfield2,  \
582                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
583                 ret = False; \
584         } \
585         s1 = fnum_find(sname1); s2 = fname_find(sname2); \
586         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
587                 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
588                        #stype1, #tfield1, #stype2, #tfield2,  \
589                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
590                 ret = False; \
591         } \
592         s1 = fname_find(sname1); s2 = fnum_find(sname2); \
593         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
594                 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
595                        #stype1, #tfield1, #stype2, #tfield2,  \
596                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
597                 ret = False; \
598         }} while (0)
599
600         VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, 
601                   "ALL_INFO",      all_info,      delete_pending);
602         VAL_CHECK("STANDARD_INFO", standard_info, directory, 
603                   "ALL_INFO",      all_info,      directory);
604         VAL_CHECK("STANDARD_INFO", standard_info, nlink, 
605                   "ALL_INFO",      all_info,      nlink);
606         VAL_CHECK("EA_INFO",       ea_info,       ea_size, 
607                   "ALL_INFO",      all_info,      ea_size);
608         VAL_CHECK("ALL_EAS",       all_eas,       ea_size, 
609                   "ALL_INFO",      all_info,      ea_size);
610         VAL_CHECK("EA_SIZE",       ea_size,       ea_size, 
611                   "ALL_INFO",      all_info,      ea_size);
612
613 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
614         s1 = fnum_find(sname); \
615         if (s1 && s1->stype.out.tfield != 0) { \
616                 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
617                        #stype, #tfield, \
618                        (unsigned)s1->stype.out.tfield); \
619         } \
620         s1 = fname_find(sname); \
621         if (s1 && s1->stype.out.tfield != 0) { \
622                 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
623                        #stype, #tfield, \
624                        (unsigned)s1->stype.out.tfield); \
625         }} while (0)
626
627         /* now get a bit fancier .... */
628         
629         /* when we set the delete disposition then the link count should drop
630            to 0 and delete_pending should be 1 */
631         
632
633 done:
634         cli_close(cli, fnum);
635         cli_unlink(cli, fname);
636
637         torture_close_connection(cli);
638         talloc_destroy(mem_ctx);
639         return ret;
640 }