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