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