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