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