r24735: Use torture API in more places.
[sharpe/samba-autobuild/.git] / source4 / torture / raw / qfileinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3    RAW_FILEINFO_* individual test suite
4    Copyright (C) Andrew Tridgell 2003
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "torture/rpc/rpc.h"
28
29 static struct {
30         const char *name;
31         enum smb_fileinfo_level level;
32         uint_t only_paths:1;
33         uint_t only_handles:1;
34         uint32_t capability_mask;
35         uint_t expected_ipc_access_denied:1;
36         NTSTATUS expected_ipc_fnum_status;
37         NTSTATUS fnum_status, fname_status;
38         union smb_fileinfo fnum_finfo, fname_finfo;
39 } levels[] = {
40         { .name = "GETATTR",
41           .level = RAW_FILEINFO_GETATTR,         
42           .only_paths = 1,
43           .only_handles = 0,
44           .expected_ipc_access_denied = 1},
45         {  .name ="GETATTRE",                  
46            .level = RAW_FILEINFO_GETATTRE,         
47            .only_paths = 0, 
48            .only_handles = 1 },
49         {  .name ="STANDARD",                  
50            .level = RAW_FILEINFO_STANDARD, },
51         {  .name ="EA_SIZE",                 
52            .level = RAW_FILEINFO_EA_SIZE },
53         {  .name ="ALL_EAS",                 
54            .level = RAW_FILEINFO_ALL_EAS,
55            .expected_ipc_fnum_status = NT_STATUS_ACCESS_DENIED,
56         },
57         {  .name ="IS_NAME_VALID",          
58            .level =  RAW_FILEINFO_IS_NAME_VALID,
59            .only_paths =  1,
60            .only_handles =  0 },
61         {  .name ="BASIC_INFO",            
62            .level =  RAW_FILEINFO_BASIC_INFO },
63         {  .name ="STANDARD_INFO",         
64            .level =  RAW_FILEINFO_STANDARD_INFO },
65         {  .name ="EA_INFO",               
66            .level =  RAW_FILEINFO_EA_INFO },
67         {  .name ="NAME_INFO",           
68            .level =  RAW_FILEINFO_NAME_INFO },
69         {  .name ="ALL_INFO",              
70            .level =  RAW_FILEINFO_ALL_INFO },
71         {  .name ="ALT_NAME_INFO",        
72            .level =  RAW_FILEINFO_ALT_NAME_INFO,
73            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
74         },
75         {  .name ="STREAM_INFO",           
76            .level =  RAW_FILEINFO_STREAM_INFO,
77            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
78         },
79         {  .name ="COMPRESSION_INFO",        
80            .level =  RAW_FILEINFO_COMPRESSION_INFO,
81            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
82         },
83         {  .name ="UNIX_BASIC_INFO",         
84            .level =  RAW_FILEINFO_UNIX_BASIC,
85            .only_paths =  0, 
86            .only_handles = 0, 
87            .capability_mask = CAP_UNIX},
88         {  .name ="UNIX_LINK_INFO",          
89            .level =  RAW_FILEINFO_UNIX_LINK, 
90            .only_paths = 0, 
91            .only_handles = 0, 
92            .capability_mask = CAP_UNIX},
93         {  .name ="BASIC_INFORMATION",      
94            .level =  RAW_FILEINFO_BASIC_INFORMATION },
95         {  .name ="STANDARD_INFORMATION",   
96            .level =  RAW_FILEINFO_STANDARD_INFORMATION },
97         {  .name ="INTERNAL_INFORMATION",   
98            .level =  RAW_FILEINFO_INTERNAL_INFORMATION },
99         {  .name ="EA_INFORMATION",        
100            .level =  RAW_FILEINFO_EA_INFORMATION },
101         { .name = "ACCESS_INFORMATION",    
102           .level =  RAW_FILEINFO_ACCESS_INFORMATION },
103         { .name = "NAME_INFORMATION",      
104           .level =  RAW_FILEINFO_NAME_INFORMATION },
105         {  .name ="POSITION_INFORMATION",  
106            .level =  RAW_FILEINFO_POSITION_INFORMATION },
107         {  .name ="MODE_INFORMATION",       
108            .level =  RAW_FILEINFO_MODE_INFORMATION },
109         {  .name ="ALIGNMENT_INFORMATION",  
110            .level =  RAW_FILEINFO_ALIGNMENT_INFORMATION },
111         {  .name ="ALL_INFORMATION",       
112            .level =  RAW_FILEINFO_ALL_INFORMATION },
113         {  .name ="ALT_NAME_INFORMATION",  
114            .level =  RAW_FILEINFO_ALT_NAME_INFORMATION,
115            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
116         },
117         {  .name ="STREAM_INFORMATION",    
118            .level =  RAW_FILEINFO_STREAM_INFORMATION,
119            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
120         },
121         { .name = "COMPRESSION_INFORMATION", 
122           .level =  RAW_FILEINFO_COMPRESSION_INFORMATION,
123           .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
124         },
125         {  .name ="NETWORK_OPEN_INFORMATION",
126            .level =  RAW_FILEINFO_NETWORK_OPEN_INFORMATION,
127            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
128         },
129         { .name = "ATTRIBUTE_TAG_INFORMATION",
130           .level =  RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION,
131           .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
132         },
133         { NULL }
134 };
135
136 /*
137   compare a dos time (2 second resolution) to a nt time
138 */
139 static int dos_nt_time_cmp(time_t t, NTTIME nt)
140 {
141         time_t t2 = nt_time_to_unix(nt);
142         if (abs(t2 - t) <= 2) return 0;
143         return t2 - t;
144 }
145
146
147 /*
148   find a level in the levels[] table
149 */
150 static union smb_fileinfo *fnum_find(const char *name)
151 {
152         int i;
153         for (i=0; levels[i].name; i++) {
154                 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
155                     strcmp(name, levels[i].name) == 0 && 
156                     !levels[i].only_paths) {
157                         return &levels[i].fnum_finfo;
158                 }
159         }
160         return NULL;
161 }
162
163 /*
164   find a level in the levels[] table
165 */
166 static union smb_fileinfo *fname_find(bool is_ipc, const char *name)
167 {
168         int i;
169         if (is_ipc) {
170                 return NULL;
171         }
172         for (i=0; levels[i].name; i++) {
173                 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
174                     strcmp(name, levels[i].name) == 0 && 
175                     !levels[i].only_handles) {
176                         return &levels[i].fname_finfo;
177                 }
178         }
179         return NULL;
180 }
181
182 /* local macros to make the code below more readable */
183 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
184         printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
185                #n1, #v1, (uint_t)s1->n1.out.v1, \
186                #n2, #v2, (uint_t)s2->n2.out.v2, \
187                __FILE__, __LINE__); \
188         ret = False; \
189 }} while(0)
190
191 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
192                                           s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
193         printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
194                #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
195                #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
196                __FILE__, __LINE__); \
197         ret = False; \
198 }} while(0)
199
200 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
201         printf("%s/%s != %s/%s at %s(%d)\n", \
202                #n1, #v1, \
203                #n2, #v2, \
204                __FILE__, __LINE__); \
205         ret = False; \
206 }} while(0)
207
208 /* used to find hints on unknown values - and to make sure 
209    we zero-fill */
210 #if 0 /* unused */
211 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
212         printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
213                #n1, #v1, \
214                (uint_t)s1->n1.out.v1, \
215                (uint_t)s1->n1.out.v1, \
216                __FILE__, __LINE__); \
217         ret = False; \
218 }} while(0)
219 #endif
220
221 /* basic testing of all RAW_FILEINFO_* calls 
222    for each call we test that it succeeds, and where possible test 
223    for consistency between the calls. 
224 */
225 static BOOL torture_raw_qfileinfo_internals(struct torture_context *torture, 
226                                             TALLOC_CTX *mem_ctx,        
227                                             struct smbcli_tree *tree, 
228                                             int fnum, const char *fname,
229                                             bool is_ipc)
230 {
231         int i;
232         BOOL ret = True;
233         int count;
234         union smb_fileinfo *s1, *s2;    
235         NTTIME correct_time;
236         uint64_t correct_size;
237         uint32_t correct_attrib;
238         const char *correct_name;
239         BOOL skip_streams = False;
240
241         /* scan all the fileinfo and pathinfo levels */
242         for (i=0; levels[i].name; i++) {
243                 if (!levels[i].only_paths) {
244                         levels[i].fnum_finfo.generic.level = levels[i].level;
245                         levels[i].fnum_finfo.generic.in.file.fnum = fnum;
246                         levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx, 
247                                                                  &levels[i].fnum_finfo);
248                 }
249
250                 if (!levels[i].only_handles) {
251                         levels[i].fname_finfo.generic.level = levels[i].level;
252                         levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
253                         levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx, 
254                                                                   &levels[i].fname_finfo);
255                 }
256         }
257
258         /* check for completely broken levels */
259         for (count=i=0; levels[i].name; i++) {
260                 uint32_t cap = tree->session->transport->negotiate.capabilities;
261                 /* see if this server claims to support this level */
262                 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
263                         continue;
264                 }
265
266                 if (is_ipc) {
267                         if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
268                         } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
269                                 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", 
270                                        levels[i].name, nt_errstr(levels[i].fname_status));
271                                 count++;
272                         }
273                         if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
274                                 printf("ERROR: fnum level %s failed, expected %s - %s\n", 
275                                        levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), 
276                                        nt_errstr(levels[i].fnum_status));
277                                 count++;
278                         }
279                 } else {
280                         if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
281                                 printf("ERROR: fnum level %s failed - %s\n", 
282                                        levels[i].name, nt_errstr(levels[i].fnum_status));
283                                 count++;
284                         }
285                         if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
286                                 printf("ERROR: fname level %s failed - %s\n", 
287                                        levels[i].name, nt_errstr(levels[i].fname_status));
288                                 count++;
289                         }
290                 }
291                 
292         }
293
294         if (count != 0) {
295                 ret = False;
296                 printf("%d levels failed\n", count);
297                 if (count > 35) {
298                         printf("too many level failures - giving up\n");
299                         goto done;
300                 }
301         }
302
303         /* see if we can do streams */
304         s1 = fnum_find("STREAM_INFO");
305         if (!s1 || s1->stream_info.out.num_streams == 0) {
306                 if (!is_ipc) {
307                         printf("STREAM_INFO broken (%d) - skipping streams checks\n",
308                                s1 ? s1->stream_info.out.num_streams : -1);
309                 }
310                 skip_streams = True;
311         }       
312
313
314         /* this code is incredibly repititive but doesn't lend itself to loops, so
315            we use lots of macros to make it less painful */
316
317         /* first off we check the levels that are supposed to be aliases. It will be quite rare for 
318            this code to fail, but we need to check it for completeness */
319
320
321
322 #define ALIAS_CHECK(sname1, sname2) \
323         do { \
324                 s1 = fnum_find(sname1);  s2 = fnum_find(sname2); \
325                 if (s1 && s2) { INFO_CHECK } \
326                 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
327                 if (s1 && s2) { INFO_CHECK } \
328                 s1 = fnum_find(sname1);  s2 = fname_find(is_ipc, sname2); \
329                 if (s1 && s2) { INFO_CHECK } \
330         } while (0)
331
332 #define INFO_CHECK \
333                 STRUCT_EQUAL(basic_info,  create_time, basic_info, create_time); \
334                 STRUCT_EQUAL(basic_info,  access_time, basic_info, access_time); \
335                 STRUCT_EQUAL(basic_info,  write_time,  basic_info, write_time); \
336                 STRUCT_EQUAL(basic_info,  change_time, basic_info, change_time); \
337                 VAL_EQUAL   (basic_info,  attrib,      basic_info, attrib);
338
339         ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
340
341 #undef INFO_CHECK
342 #define INFO_CHECK \
343                 VAL_EQUAL(standard_info,  alloc_size,     standard_info, alloc_size); \
344                 VAL_EQUAL(standard_info,  size,           standard_info, size); \
345                 VAL_EQUAL(standard_info,  nlink,          standard_info, nlink); \
346                 VAL_EQUAL(standard_info,  delete_pending, standard_info, delete_pending); \
347                 VAL_EQUAL(standard_info,  directory,      standard_info, directory);
348
349         ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
350
351 #undef INFO_CHECK
352 #define INFO_CHECK \
353                 VAL_EQUAL(ea_info,  ea_size,     ea_info, ea_size);
354
355         ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
356
357 #undef INFO_CHECK
358 #define INFO_CHECK \
359                 STR_EQUAL(name_info,  fname,   name_info, fname);
360
361         ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
362
363 #undef INFO_CHECK
364 #define INFO_CHECK \
365                 STRUCT_EQUAL(all_info,  create_time,           all_info, create_time); \
366                 STRUCT_EQUAL(all_info,  access_time,           all_info, access_time); \
367                 STRUCT_EQUAL(all_info,  write_time,            all_info, write_time); \
368                 STRUCT_EQUAL(all_info,  change_time,           all_info, change_time); \
369                    VAL_EQUAL(all_info,  attrib,                all_info, attrib); \
370                    VAL_EQUAL(all_info,  alloc_size,            all_info, alloc_size); \
371                    VAL_EQUAL(all_info,  size,                  all_info, size); \
372                    VAL_EQUAL(all_info,  nlink,                 all_info, nlink); \
373                    VAL_EQUAL(all_info,  delete_pending,        all_info, delete_pending); \
374                    VAL_EQUAL(all_info,  directory,             all_info, directory); \
375                    VAL_EQUAL(all_info,  ea_size,               all_info, ea_size); \
376                    STR_EQUAL(all_info,  fname,                 all_info, fname);
377
378         ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
379
380 #undef INFO_CHECK
381 #define INFO_CHECK \
382                 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
383                 VAL_EQUAL(compression_info, format,         compression_info, format); \
384                 VAL_EQUAL(compression_info, unit_shift,     compression_info, unit_shift); \
385                 VAL_EQUAL(compression_info, chunk_shift,    compression_info, chunk_shift); \
386                 VAL_EQUAL(compression_info, cluster_shift,  compression_info, cluster_shift);
387
388         ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
389
390
391 #undef INFO_CHECK
392 #define INFO_CHECK \
393                 STR_EQUAL(alt_name_info,  fname,   alt_name_info, fname);
394
395         ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
396
397
398 #define TIME_CHECK_NT(sname, stype, tfield) do { \
399         s1 = fnum_find(sname); \
400         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
401                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
402                        nt_time_string(mem_ctx, s1->stype.out.tfield), \
403                        nt_time_string(mem_ctx, correct_time)); \
404                 ret = False; \
405         } \
406         s1 = fname_find(is_ipc, sname); \
407         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
408                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
409                        nt_time_string(mem_ctx, s1->stype.out.tfield), \
410                        nt_time_string(mem_ctx, correct_time)); \
411                 ret = False; \
412         }} while (0)
413
414 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
415         s1 = fnum_find(sname); \
416         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
417                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
418                        timestring(mem_ctx, s1->stype.out.tfield), \
419                        nt_time_string(mem_ctx, correct_time)); \
420                 ret = False; \
421         } \
422         s1 = fname_find(is_ipc, sname); \
423         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
424                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
425                        timestring(mem_ctx, s1->stype.out.tfield), \
426                        nt_time_string(mem_ctx, correct_time)); \
427                 ret = False; \
428         }} while (0)
429
430 #if 0 /* unused */
431 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
432         s1 = fnum_find(sname); \
433         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
434                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
435                        timestring(mem_ctx, s1->stype.out.tfield), \
436                        nt_time_string(mem_ctx, correct_time)); \
437                 ret = False; \
438         } \
439         s1 = fname_find(is_ipc, sname); \
440         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
441                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
442                        timestring(mem_ctx, s1->stype.out.tfield), \
443                        nt_time_string(mem_ctx, correct_time)); \
444                 ret = False; \
445         }} while (0)
446 #endif
447
448         /* now check that all the times that are supposed to be equal are correct */
449         s1 = fnum_find("BASIC_INFO");
450         correct_time = s1->basic_info.out.create_time;
451         printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
452
453         TIME_CHECK_NT ("BASIC_INFO",               basic_info, create_time);
454         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, create_time);
455         TIME_CHECK_DOS("GETATTRE",                 getattre,   create_time);
456         TIME_CHECK_DOS("STANDARD",                 standard,   create_time);
457         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    create_time);
458         TIME_CHECK_NT ("ALL_INFO",                 all_info,   create_time);
459         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
460
461         s1 = fnum_find("BASIC_INFO");
462         correct_time = s1->basic_info.out.access_time;
463         printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
464
465         TIME_CHECK_NT ("BASIC_INFO",               basic_info, access_time);
466         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, access_time);
467         TIME_CHECK_DOS("GETATTRE",                 getattre,   access_time);
468         TIME_CHECK_DOS("STANDARD",                 standard,   access_time);
469         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    access_time);
470         TIME_CHECK_NT ("ALL_INFO",                 all_info,   access_time);
471         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
472
473         s1 = fnum_find("BASIC_INFO");
474         correct_time = s1->basic_info.out.write_time;
475         printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
476
477         TIME_CHECK_NT ("BASIC_INFO",               basic_info, write_time);
478         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, write_time);
479         TIME_CHECK_DOS("GETATTR",                  getattr,    write_time);
480         TIME_CHECK_DOS("GETATTRE",                 getattre,   write_time);
481         TIME_CHECK_DOS("STANDARD",                 standard,   write_time);
482         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    write_time);
483         TIME_CHECK_NT ("ALL_INFO",                 all_info,   write_time);
484         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
485
486         s1 = fnum_find("BASIC_INFO");
487         correct_time = s1->basic_info.out.change_time;
488         printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
489
490         TIME_CHECK_NT ("BASIC_INFO",               basic_info, change_time);
491         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, change_time);
492         TIME_CHECK_NT ("ALL_INFO",                 all_info,   change_time);
493         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
494
495
496 #define SIZE_CHECK(sname, stype, tfield) do { \
497         s1 = fnum_find(sname); \
498         if (s1 && s1->stype.out.tfield != correct_size) { \
499                 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
500                        (uint_t)s1->stype.out.tfield, \
501                        (uint_t)correct_size); \
502                 ret = False; \
503         } \
504         s1 = fname_find(is_ipc, sname); \
505         if (s1 && s1->stype.out.tfield != correct_size) { \
506                 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
507                        (uint_t)s1->stype.out.tfield, \
508                        (uint_t)correct_size); \
509                 ret = False; \
510         }} while (0)
511
512         s1 = fnum_find("STANDARD_INFO");
513         correct_size = s1->standard_info.out.size;
514         printf("size: %u\n", (uint_t)correct_size);
515         
516         SIZE_CHECK("GETATTR",                  getattr,                  size);
517         SIZE_CHECK("GETATTRE",                 getattre,                 size);
518         SIZE_CHECK("STANDARD",                 standard,                 size);
519         SIZE_CHECK("EA_SIZE",                  ea_size,                  size);
520         SIZE_CHECK("STANDARD_INFO",            standard_info,            size);
521         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            size);
522         SIZE_CHECK("ALL_INFO",                 all_info,                 size);
523         SIZE_CHECK("ALL_INFORMATION",          all_info,                 size);
524         SIZE_CHECK("COMPRESSION_INFO",         compression_info,         compressed_size);
525         SIZE_CHECK("COMPRESSION_INFORMATION",  compression_info,         compressed_size);
526         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
527         if (!skip_streams) {
528                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].size);
529                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].size);
530         }
531
532
533         s1 = fnum_find("STANDARD_INFO");
534         correct_size = s1->standard_info.out.alloc_size;
535         printf("alloc_size: %u\n", (uint_t)correct_size);
536         
537         SIZE_CHECK("GETATTRE",                 getattre,                 alloc_size);
538         SIZE_CHECK("STANDARD",                 standard,                 alloc_size);
539         SIZE_CHECK("EA_SIZE",                  ea_size,                  alloc_size);
540         SIZE_CHECK("STANDARD_INFO",            standard_info,            alloc_size);
541         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            alloc_size);
542         SIZE_CHECK("ALL_INFO",                 all_info,                 alloc_size);
543         SIZE_CHECK("ALL_INFORMATION",          all_info,                 alloc_size);
544         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
545         if (!skip_streams) {
546                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].alloc_size);
547                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].alloc_size);
548         }
549
550 #define ATTRIB_CHECK(sname, stype, tfield) do { \
551         s1 = fnum_find(sname); \
552         if (s1 && s1->stype.out.tfield != correct_attrib) { \
553                 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
554                        (uint_t)s1->stype.out.tfield, \
555                        (uint_t)correct_attrib); \
556                 ret = False; \
557         } \
558         s1 = fname_find(is_ipc, sname); \
559         if (s1 && s1->stype.out.tfield != correct_attrib) { \
560                 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
561                        (uint_t)s1->stype.out.tfield, \
562                        (uint_t)correct_attrib); \
563                 ret = False; \
564         }} while (0)
565
566         s1 = fnum_find("BASIC_INFO");
567         correct_attrib = s1->basic_info.out.attrib;
568         printf("attrib: 0x%x\n", (uint_t)correct_attrib);
569         
570         ATTRIB_CHECK("GETATTR",                   getattr,                   attrib);
571         if (!is_ipc) {
572                 ATTRIB_CHECK("GETATTRE",                  getattre,                  attrib);
573                 ATTRIB_CHECK("STANDARD",                  standard,                  attrib);
574                 ATTRIB_CHECK("EA_SIZE",                   ea_size,                   attrib);
575         }
576         ATTRIB_CHECK("BASIC_INFO",                basic_info,                attrib);
577         ATTRIB_CHECK("BASIC_INFORMATION",         basic_info,                attrib);
578         ATTRIB_CHECK("ALL_INFO",                  all_info,                  attrib);
579         ATTRIB_CHECK("ALL_INFORMATION",           all_info,                  attrib);
580         ATTRIB_CHECK("NETWORK_OPEN_INFORMATION",  network_open_information,  attrib);
581         ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
582
583         correct_name = fname;
584         printf("name: %s\n", correct_name);
585
586 #define NAME_CHECK(sname, stype, tfield, flags) do { \
587         s1 = fnum_find(sname); \
588         if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
589                         wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
590                 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
591                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
592                 ret = False; \
593         } \
594         s1 = fname_find(is_ipc, sname); \
595         if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
596                         wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
597                 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
598                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
599                 ret = False; \
600         }} while (0)
601
602         NAME_CHECK("NAME_INFO",        name_info, fname, STR_UNICODE);
603         NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
604
605         /* the ALL_INFO file name is the full path on the filesystem */
606         s1 = fnum_find("ALL_INFO");
607         if (s1 && !s1->all_info.out.fname.s) {
608                 printf("ALL_INFO didn't give a filename\n");
609                 ret = False;
610         }
611         if (s1 && s1->all_info.out.fname.s) {
612                 char *p = strrchr(s1->all_info.out.fname.s, '\\');
613                 if (!p) {
614                         printf("Not a full path in all_info/fname? - '%s'\n", 
615                                s1->all_info.out.fname.s);
616                         ret = False;
617                 } else {
618                         if (strcmp_safe(correct_name, p) != 0) {
619                                 printf("incorrect basename in all_info/fname - '%s'\n",
620                                        s1->all_info.out.fname.s);
621                                 ret = False;
622                         }
623                 }
624                 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
625                         printf("Should not null terminate all_info/fname\n");
626                         ret = False;
627                 }
628         }
629
630         s1 = fnum_find("ALT_NAME_INFO");
631         if (s1) {
632                 correct_name = s1->alt_name_info.out.fname.s;
633                 printf("alt_name: %s\n", correct_name);
634                 
635                 NAME_CHECK("ALT_NAME_INFO",        alt_name_info, fname, STR_UNICODE);
636                 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
637                 
638                 /* and make sure we can open by alternate name */
639                 smbcli_close(tree, fnum);
640                 fnum = smbcli_nt_create_full(tree, correct_name, 0, 
641                                              SEC_RIGHTS_FILE_ALL,
642                                              FILE_ATTRIBUTE_NORMAL,
643                                              NTCREATEX_SHARE_ACCESS_DELETE|
644                                              NTCREATEX_SHARE_ACCESS_READ|
645                                              NTCREATEX_SHARE_ACCESS_WRITE, 
646                                              NTCREATEX_DISP_OVERWRITE_IF, 
647                                              0, 0);
648                 if (fnum == -1) {
649                         printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
650                         ret = False;
651                 }
652                 
653                 if (!skip_streams) {
654                         correct_name = "::$DATA";
655                         printf("stream_name: %s\n", correct_name);
656                         
657                         NAME_CHECK("STREAM_INFO",        stream_info, streams[0].stream_name, STR_UNICODE);
658                         NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
659                 }
660         }
661                 
662         /* make sure the EAs look right */
663         s1 = fnum_find("ALL_EAS");
664         s2 = fnum_find("ALL_INFO");
665         if (s1) {
666                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
667                         printf("  flags=%d %s=%*.*s\n", 
668                                s1->all_eas.out.eas[i].flags,
669                                s1->all_eas.out.eas[i].name.s,
670                                (int)s1->all_eas.out.eas[i].value.length,
671                                (int)s1->all_eas.out.eas[i].value.length,
672                                s1->all_eas.out.eas[i].value.data);
673                 }
674         }
675         if (s1 && s2) {
676                 if (s1->all_eas.out.num_eas == 0) {
677                         if (s2->all_info.out.ea_size != 0) {
678                                 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
679                                        s2->all_info.out.ea_size);
680                         }
681                 } else {
682                         if (s2->all_info.out.ea_size != 
683                             ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
684                                 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
685                                        (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
686                                        (int)s2->all_info.out.ea_size);
687                         }
688                 }
689         }
690         s2 = fname_find(is_ipc, "ALL_EAS");
691         if (s2) {
692                 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
693                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
694                         VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
695                         STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
696                         VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
697                 }
698         }
699
700 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
701         s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
702         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
703                 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
704                        #stype1, #tfield1, #stype2, #tfield2,  \
705                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
706                 ret = False; \
707         } \
708         s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
709         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
710                 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
711                        #stype1, #tfield1, #stype2, #tfield2,  \
712                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
713                 ret = False; \
714         } \
715         s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
716         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
717                 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
718                        #stype1, #tfield1, #stype2, #tfield2,  \
719                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
720                 ret = False; \
721         } \
722         s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
723         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
724                 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
725                        #stype1, #tfield1, #stype2, #tfield2,  \
726                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
727                 ret = False; \
728         }} while (0)
729
730         VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, 
731                   "ALL_INFO",      all_info,      delete_pending);
732         VAL_CHECK("STANDARD_INFO", standard_info, directory, 
733                   "ALL_INFO",      all_info,      directory);
734         VAL_CHECK("STANDARD_INFO", standard_info, nlink, 
735                   "ALL_INFO",      all_info,      nlink);
736         s1 = fnum_find("BASIC_INFO");
737         if (s1 && is_ipc) {
738                 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
739                         printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
740                         ret = False;
741                 }
742         }
743         s1 = fnum_find("STANDARD_INFO");
744         if (s1 && is_ipc) {
745                 if (s1->standard_info.out.nlink != 1) {
746                         printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
747                         ret = False;
748                 }
749                 if (s1->standard_info.out.delete_pending != 1) {
750                         printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
751                         ret = False;
752                 }
753         }
754         VAL_CHECK("EA_INFO",       ea_info,       ea_size, 
755                   "ALL_INFO",      all_info,      ea_size);
756         if (!is_ipc) {
757                 VAL_CHECK("EA_SIZE",       ea_size,       ea_size, 
758                           "ALL_INFO",      all_info,      ea_size);
759         }
760
761 #define NAME_PATH_CHECK(sname, stype, field) do { \
762         s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
763         if (s1 && s2) { \
764                 VAL_EQUAL(stype, field, stype, field); \
765         } \
766 } while (0)
767
768
769         s1 = fnum_find("INTERNAL_INFORMATION");
770         if (s1) {
771                 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
772         }
773
774         NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
775         NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
776         if (s1 && s2) {
777                 printf("fnum pos = %.0f, fname pos = %.0f\n",
778                        (double)s2->position_information.out.position,
779                        (double)s1->position_information.out.position );
780         }
781         NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
782         NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
783         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
784         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
785
786 #if 0
787         /* these are expected to differ */
788         NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
789 #endif
790
791 #if 0 /* unused */
792 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
793         s1 = fnum_find(sname); \
794         if (s1 && s1->stype.out.tfield != 0) { \
795                 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
796                        #stype, #tfield, \
797                        (uint_t)s1->stype.out.tfield); \
798         } \
799         s1 = fname_find(is_ipc, sname); \
800         if (s1 && s1->stype.out.tfield != 0) { \
801                 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
802                        #stype, #tfield, \
803                        (uint_t)s1->stype.out.tfield); \
804         }} while (0)
805 #endif
806         /* now get a bit fancier .... */
807         
808         /* when we set the delete disposition then the link count should drop
809            to 0 and delete_pending should be 1 */
810         
811
812 done:
813
814         return ret;
815 }
816
817 /* basic testing of all RAW_FILEINFO_* calls 
818    for each call we test that it succeeds, and where possible test 
819    for consistency between the calls. 
820 */
821 bool torture_raw_qfileinfo(struct torture_context *torture, 
822                                                    struct smbcli_state *cli)
823 {
824         int fnum;
825         bool ret;
826         const char *fname = "\\torture_qfileinfo.txt";
827
828         fnum = create_complex_file(cli, torture, fname);
829         if (fnum == -1) {
830                 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
831                 return false;
832         }
833
834         ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, False /* is_ipc */);
835         
836         smbcli_close(cli->tree, fnum);
837         smbcli_unlink(cli->tree, fname);
838
839         return ret;
840 }
841
842 bool torture_raw_qfileinfo_pipe(struct torture_context *torture, 
843                                                                 struct smbcli_state *cli)
844 {
845         bool ret = true;
846         int fnum;
847         const char *fname = "\\lsass";
848         struct dcerpc_pipe *p;
849         struct smbcli_tree *ipc_tree;
850         NTSTATUS status;
851
852         if (!(p = dcerpc_pipe_init(torture, 
853                                    cli->tree->session->transport->socket->event.ctx))) {
854                 return False;
855         }
856
857         status = dcerpc_pipe_open_smb(p, cli->tree, fname);
858         if (!NT_STATUS_IS_OK(status)) {
859                 d_printf("dcerpc_pipe_open_smb failed: %s\n",
860                          nt_errstr(status));
861                 talloc_free(p);
862                 return False;
863         }
864
865         ipc_tree = dcerpc_smb_tree(p->conn);
866         fnum = dcerpc_smb_fnum(p->conn);
867
868         ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, True /* is_ipc */);
869         
870         talloc_free(p);
871         return ret;
872 }