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