r23792: convert Samba4 to GPLv3
[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    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, TALLOC_CTX *mem_ctx,       
226                                             struct smbcli_tree *tree, int fnum, const char *fname,
227         bool is_ipc)
228 {
229         int i;
230         BOOL ret = True;
231         int count;
232         union smb_fileinfo *s1, *s2;    
233         NTTIME correct_time;
234         uint64_t correct_size;
235         uint32_t correct_attrib;
236         const char *correct_name;
237         BOOL skip_streams = False;
238
239         /* scan all the fileinfo and pathinfo levels */
240         for (i=0; levels[i].name; i++) {
241                 if (!levels[i].only_paths) {
242                         levels[i].fnum_finfo.generic.level = levels[i].level;
243                         levels[i].fnum_finfo.generic.in.file.fnum = fnum;
244                         levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx, 
245                                                                  &levels[i].fnum_finfo);
246                 }
247
248                 if (!levels[i].only_handles) {
249                         levels[i].fname_finfo.generic.level = levels[i].level;
250                         levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
251                         levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx, 
252                                                                   &levels[i].fname_finfo);
253                 }
254         }
255
256         /* check for completely broken levels */
257         for (count=i=0; levels[i].name; i++) {
258                 uint32_t cap = tree->session->transport->negotiate.capabilities;
259                 /* see if this server claims to support this level */
260                 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
261                         continue;
262                 }
263
264                 if (is_ipc) {
265                         if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
266                         } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
267                                 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", 
268                                        levels[i].name, nt_errstr(levels[i].fname_status));
269                                 count++;
270                         }
271                         if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
272                                 printf("ERROR: fnum level %s failed, expected %s - %s\n", 
273                                        levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), 
274                                        nt_errstr(levels[i].fnum_status));
275                                 count++;
276                         }
277                 } else {
278                         if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
279                                 printf("ERROR: fnum level %s failed - %s\n", 
280                                        levels[i].name, nt_errstr(levels[i].fnum_status));
281                                 count++;
282                         }
283                         if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
284                                 printf("ERROR: fname level %s failed - %s\n", 
285                                        levels[i].name, nt_errstr(levels[i].fname_status));
286                                 count++;
287                         }
288                 }
289                 
290         }
291
292         if (count != 0) {
293                 ret = False;
294                 printf("%d levels failed\n", count);
295                 if (count > 35) {
296                         printf("too many level failures - giving up\n");
297                         goto done;
298                 }
299         }
300
301         /* see if we can do streams */
302         s1 = fnum_find("STREAM_INFO");
303         if (!s1 || s1->stream_info.out.num_streams == 0) {
304                 if (!is_ipc) {
305                         printf("STREAM_INFO broken (%d) - skipping streams checks\n",
306                                s1 ? s1->stream_info.out.num_streams : -1);
307                 }
308                 skip_streams = True;
309         }       
310
311
312         /* this code is incredibly repititive but doesn't lend itself to loops, so
313            we use lots of macros to make it less painful */
314
315         /* first off we check the levels that are supposed to be aliases. It will be quite rare for 
316            this code to fail, but we need to check it for completeness */
317
318
319
320 #define ALIAS_CHECK(sname1, sname2) \
321         do { \
322                 s1 = fnum_find(sname1);  s2 = fnum_find(sname2); \
323                 if (s1 && s2) { INFO_CHECK } \
324                 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
325                 if (s1 && s2) { INFO_CHECK } \
326                 s1 = fnum_find(sname1);  s2 = fname_find(is_ipc, sname2); \
327                 if (s1 && s2) { INFO_CHECK } \
328         } while (0)
329
330 #define INFO_CHECK \
331                 STRUCT_EQUAL(basic_info,  create_time, basic_info, create_time); \
332                 STRUCT_EQUAL(basic_info,  access_time, basic_info, access_time); \
333                 STRUCT_EQUAL(basic_info,  write_time,  basic_info, write_time); \
334                 STRUCT_EQUAL(basic_info,  change_time, basic_info, change_time); \
335                 VAL_EQUAL   (basic_info,  attrib,      basic_info, attrib);
336
337         ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
338
339 #undef INFO_CHECK
340 #define INFO_CHECK \
341                 VAL_EQUAL(standard_info,  alloc_size,     standard_info, alloc_size); \
342                 VAL_EQUAL(standard_info,  size,           standard_info, size); \
343                 VAL_EQUAL(standard_info,  nlink,          standard_info, nlink); \
344                 VAL_EQUAL(standard_info,  delete_pending, standard_info, delete_pending); \
345                 VAL_EQUAL(standard_info,  directory,      standard_info, directory);
346
347         ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
348
349 #undef INFO_CHECK
350 #define INFO_CHECK \
351                 VAL_EQUAL(ea_info,  ea_size,     ea_info, ea_size);
352
353         ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
354
355 #undef INFO_CHECK
356 #define INFO_CHECK \
357                 STR_EQUAL(name_info,  fname,   name_info, fname);
358
359         ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
360
361 #undef INFO_CHECK
362 #define INFO_CHECK \
363                 STRUCT_EQUAL(all_info,  create_time,           all_info, create_time); \
364                 STRUCT_EQUAL(all_info,  access_time,           all_info, access_time); \
365                 STRUCT_EQUAL(all_info,  write_time,            all_info, write_time); \
366                 STRUCT_EQUAL(all_info,  change_time,           all_info, change_time); \
367                    VAL_EQUAL(all_info,  attrib,                all_info, attrib); \
368                    VAL_EQUAL(all_info,  alloc_size,            all_info, alloc_size); \
369                    VAL_EQUAL(all_info,  size,                  all_info, size); \
370                    VAL_EQUAL(all_info,  nlink,                 all_info, nlink); \
371                    VAL_EQUAL(all_info,  delete_pending,        all_info, delete_pending); \
372                    VAL_EQUAL(all_info,  directory,             all_info, directory); \
373                    VAL_EQUAL(all_info,  ea_size,               all_info, ea_size); \
374                    STR_EQUAL(all_info,  fname,                 all_info, fname);
375
376         ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
377
378 #undef INFO_CHECK
379 #define INFO_CHECK \
380                 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
381                 VAL_EQUAL(compression_info, format,         compression_info, format); \
382                 VAL_EQUAL(compression_info, unit_shift,     compression_info, unit_shift); \
383                 VAL_EQUAL(compression_info, chunk_shift,    compression_info, chunk_shift); \
384                 VAL_EQUAL(compression_info, cluster_shift,  compression_info, cluster_shift);
385
386         ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
387
388
389 #undef INFO_CHECK
390 #define INFO_CHECK \
391                 STR_EQUAL(alt_name_info,  fname,   alt_name_info, fname);
392
393         ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
394
395
396 #define TIME_CHECK_NT(sname, stype, tfield) do { \
397         s1 = fnum_find(sname); \
398         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
399                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
400                        nt_time_string(mem_ctx, s1->stype.out.tfield), \
401                        nt_time_string(mem_ctx, correct_time)); \
402                 ret = False; \
403         } \
404         s1 = fname_find(is_ipc, sname); \
405         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
406                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
407                        nt_time_string(mem_ctx, s1->stype.out.tfield), \
408                        nt_time_string(mem_ctx, correct_time)); \
409                 ret = False; \
410         }} while (0)
411
412 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
413         s1 = fnum_find(sname); \
414         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
415                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
416                        timestring(mem_ctx, s1->stype.out.tfield), \
417                        nt_time_string(mem_ctx, correct_time)); \
418                 ret = False; \
419         } \
420         s1 = fname_find(is_ipc, sname); \
421         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
422                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
423                        timestring(mem_ctx, s1->stype.out.tfield), \
424                        nt_time_string(mem_ctx, correct_time)); \
425                 ret = False; \
426         }} while (0)
427
428 #if 0 /* unused */
429 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
430         s1 = fnum_find(sname); \
431         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
432                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
433                        timestring(mem_ctx, s1->stype.out.tfield), \
434                        nt_time_string(mem_ctx, correct_time)); \
435                 ret = False; \
436         } \
437         s1 = fname_find(is_ipc, sname); \
438         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
439                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
440                        timestring(mem_ctx, s1->stype.out.tfield), \
441                        nt_time_string(mem_ctx, correct_time)); \
442                 ret = False; \
443         }} while (0)
444 #endif
445
446         /* now check that all the times that are supposed to be equal are correct */
447         s1 = fnum_find("BASIC_INFO");
448         correct_time = s1->basic_info.out.create_time;
449         printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
450
451         TIME_CHECK_NT ("BASIC_INFO",               basic_info, create_time);
452         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, create_time);
453         TIME_CHECK_DOS("GETATTRE",                 getattre,   create_time);
454         TIME_CHECK_DOS("STANDARD",                 standard,   create_time);
455         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    create_time);
456         TIME_CHECK_NT ("ALL_INFO",                 all_info,   create_time);
457         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
458
459         s1 = fnum_find("BASIC_INFO");
460         correct_time = s1->basic_info.out.access_time;
461         printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
462
463         TIME_CHECK_NT ("BASIC_INFO",               basic_info, access_time);
464         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, access_time);
465         TIME_CHECK_DOS("GETATTRE",                 getattre,   access_time);
466         TIME_CHECK_DOS("STANDARD",                 standard,   access_time);
467         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    access_time);
468         TIME_CHECK_NT ("ALL_INFO",                 all_info,   access_time);
469         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
470
471         s1 = fnum_find("BASIC_INFO");
472         correct_time = s1->basic_info.out.write_time;
473         printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
474
475         TIME_CHECK_NT ("BASIC_INFO",               basic_info, write_time);
476         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, write_time);
477         TIME_CHECK_DOS("GETATTR",                  getattr,    write_time);
478         TIME_CHECK_DOS("GETATTRE",                 getattre,   write_time);
479         TIME_CHECK_DOS("STANDARD",                 standard,   write_time);
480         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    write_time);
481         TIME_CHECK_NT ("ALL_INFO",                 all_info,   write_time);
482         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
483
484         s1 = fnum_find("BASIC_INFO");
485         correct_time = s1->basic_info.out.change_time;
486         printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
487
488         TIME_CHECK_NT ("BASIC_INFO",               basic_info, change_time);
489         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, change_time);
490         TIME_CHECK_NT ("ALL_INFO",                 all_info,   change_time);
491         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
492
493
494 #define SIZE_CHECK(sname, stype, tfield) do { \
495         s1 = fnum_find(sname); \
496         if (s1 && s1->stype.out.tfield != correct_size) { \
497                 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
498                        (uint_t)s1->stype.out.tfield, \
499                        (uint_t)correct_size); \
500                 ret = False; \
501         } \
502         s1 = fname_find(is_ipc, sname); \
503         if (s1 && s1->stype.out.tfield != correct_size) { \
504                 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
505                        (uint_t)s1->stype.out.tfield, \
506                        (uint_t)correct_size); \
507                 ret = False; \
508         }} while (0)
509
510         s1 = fnum_find("STANDARD_INFO");
511         correct_size = s1->standard_info.out.size;
512         printf("size: %u\n", (uint_t)correct_size);
513         
514         SIZE_CHECK("GETATTR",                  getattr,                  size);
515         SIZE_CHECK("GETATTRE",                 getattre,                 size);
516         SIZE_CHECK("STANDARD",                 standard,                 size);
517         SIZE_CHECK("EA_SIZE",                  ea_size,                  size);
518         SIZE_CHECK("STANDARD_INFO",            standard_info,            size);
519         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            size);
520         SIZE_CHECK("ALL_INFO",                 all_info,                 size);
521         SIZE_CHECK("ALL_INFORMATION",          all_info,                 size);
522         SIZE_CHECK("COMPRESSION_INFO",         compression_info,         compressed_size);
523         SIZE_CHECK("COMPRESSION_INFORMATION",  compression_info,         compressed_size);
524         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
525         if (!skip_streams) {
526                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].size);
527                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].size);
528         }
529
530
531         s1 = fnum_find("STANDARD_INFO");
532         correct_size = s1->standard_info.out.alloc_size;
533         printf("alloc_size: %u\n", (uint_t)correct_size);
534         
535         SIZE_CHECK("GETATTRE",                 getattre,                 alloc_size);
536         SIZE_CHECK("STANDARD",                 standard,                 alloc_size);
537         SIZE_CHECK("EA_SIZE",                  ea_size,                  alloc_size);
538         SIZE_CHECK("STANDARD_INFO",            standard_info,            alloc_size);
539         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            alloc_size);
540         SIZE_CHECK("ALL_INFO",                 all_info,                 alloc_size);
541         SIZE_CHECK("ALL_INFORMATION",          all_info,                 alloc_size);
542         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
543         if (!skip_streams) {
544                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].alloc_size);
545                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].alloc_size);
546         }
547
548 #define ATTRIB_CHECK(sname, stype, tfield) do { \
549         s1 = fnum_find(sname); \
550         if (s1 && s1->stype.out.tfield != correct_attrib) { \
551                 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
552                        (uint_t)s1->stype.out.tfield, \
553                        (uint_t)correct_attrib); \
554                 ret = False; \
555         } \
556         s1 = fname_find(is_ipc, sname); \
557         if (s1 && s1->stype.out.tfield != correct_attrib) { \
558                 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
559                        (uint_t)s1->stype.out.tfield, \
560                        (uint_t)correct_attrib); \
561                 ret = False; \
562         }} while (0)
563
564         s1 = fnum_find("BASIC_INFO");
565         correct_attrib = s1->basic_info.out.attrib;
566         printf("attrib: 0x%x\n", (uint_t)correct_attrib);
567         
568         ATTRIB_CHECK("GETATTR",                   getattr,                   attrib);
569         if (!is_ipc) {
570                 ATTRIB_CHECK("GETATTRE",                  getattre,                  attrib);
571                 ATTRIB_CHECK("STANDARD",                  standard,                  attrib);
572                 ATTRIB_CHECK("EA_SIZE",                   ea_size,                   attrib);
573         }
574         ATTRIB_CHECK("BASIC_INFO",                basic_info,                attrib);
575         ATTRIB_CHECK("BASIC_INFORMATION",         basic_info,                attrib);
576         ATTRIB_CHECK("ALL_INFO",                  all_info,                  attrib);
577         ATTRIB_CHECK("ALL_INFORMATION",           all_info,                  attrib);
578         ATTRIB_CHECK("NETWORK_OPEN_INFORMATION",  network_open_information,  attrib);
579         ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
580
581         correct_name = fname;
582         printf("name: %s\n", correct_name);
583
584 #define NAME_CHECK(sname, stype, tfield, flags) do { \
585         s1 = fnum_find(sname); \
586         if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
587                         wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
588                 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
589                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
590                 ret = False; \
591         } \
592         s1 = fname_find(is_ipc, sname); \
593         if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
594                         wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
595                 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
596                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
597                 ret = False; \
598         }} while (0)
599
600         NAME_CHECK("NAME_INFO",        name_info, fname, STR_UNICODE);
601         NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
602
603         /* the ALL_INFO file name is the full path on the filesystem */
604         s1 = fnum_find("ALL_INFO");
605         if (s1 && !s1->all_info.out.fname.s) {
606                 printf("ALL_INFO didn't give a filename\n");
607                 ret = False;
608         }
609         if (s1 && s1->all_info.out.fname.s) {
610                 char *p = strrchr(s1->all_info.out.fname.s, '\\');
611                 if (!p) {
612                         printf("Not a full path in all_info/fname? - '%s'\n", 
613                                s1->all_info.out.fname.s);
614                         ret = False;
615                 } else {
616                         if (strcmp_safe(correct_name, p) != 0) {
617                                 printf("incorrect basename in all_info/fname - '%s'\n",
618                                        s1->all_info.out.fname.s);
619                                 ret = False;
620                         }
621                 }
622                 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
623                         printf("Should not null terminate all_info/fname\n");
624                         ret = False;
625                 }
626         }
627
628         s1 = fnum_find("ALT_NAME_INFO");
629         if (s1) {
630                 correct_name = s1->alt_name_info.out.fname.s;
631                 printf("alt_name: %s\n", correct_name);
632                 
633                 NAME_CHECK("ALT_NAME_INFO",        alt_name_info, fname, STR_UNICODE);
634                 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
635                 
636                 /* and make sure we can open by alternate name */
637                 smbcli_close(tree, fnum);
638                 fnum = smbcli_nt_create_full(tree, correct_name, 0, 
639                                              SEC_RIGHTS_FILE_ALL,
640                                              FILE_ATTRIBUTE_NORMAL,
641                                              NTCREATEX_SHARE_ACCESS_DELETE|
642                                              NTCREATEX_SHARE_ACCESS_READ|
643                                              NTCREATEX_SHARE_ACCESS_WRITE, 
644                                              NTCREATEX_DISP_OVERWRITE_IF, 
645                                              0, 0);
646                 if (fnum == -1) {
647                         printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
648                         ret = False;
649                 }
650                 
651                 if (!skip_streams) {
652                         correct_name = "::$DATA";
653                         printf("stream_name: %s\n", correct_name);
654                         
655                         NAME_CHECK("STREAM_INFO",        stream_info, streams[0].stream_name, STR_UNICODE);
656                         NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
657                 }
658         }
659                 
660         /* make sure the EAs look right */
661         s1 = fnum_find("ALL_EAS");
662         s2 = fnum_find("ALL_INFO");
663         if (s1) {
664                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
665                         printf("  flags=%d %s=%*.*s\n", 
666                                s1->all_eas.out.eas[i].flags,
667                                s1->all_eas.out.eas[i].name.s,
668                                (int)s1->all_eas.out.eas[i].value.length,
669                                (int)s1->all_eas.out.eas[i].value.length,
670                                s1->all_eas.out.eas[i].value.data);
671                 }
672         }
673         if (s1 && s2) {
674                 if (s1->all_eas.out.num_eas == 0) {
675                         if (s2->all_info.out.ea_size != 0) {
676                                 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
677                                        s2->all_info.out.ea_size);
678                         }
679                 } else {
680                         if (s2->all_info.out.ea_size != 
681                             ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
682                                 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
683                                        (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
684                                        (int)s2->all_info.out.ea_size);
685                         }
686                 }
687         }
688         s2 = fname_find(is_ipc, "ALL_EAS");
689         if (s2) {
690                 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
691                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
692                         VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
693                         STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
694                         VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
695                 }
696         }
697
698 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
699         s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
700         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
701                 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
702                        #stype1, #tfield1, #stype2, #tfield2,  \
703                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
704                 ret = False; \
705         } \
706         s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
707         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
708                 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
709                        #stype1, #tfield1, #stype2, #tfield2,  \
710                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
711                 ret = False; \
712         } \
713         s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
714         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
715                 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
716                        #stype1, #tfield1, #stype2, #tfield2,  \
717                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
718                 ret = False; \
719         } \
720         s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
721         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
722                 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
723                        #stype1, #tfield1, #stype2, #tfield2,  \
724                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
725                 ret = False; \
726         }} while (0)
727
728         VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, 
729                   "ALL_INFO",      all_info,      delete_pending);
730         VAL_CHECK("STANDARD_INFO", standard_info, directory, 
731                   "ALL_INFO",      all_info,      directory);
732         VAL_CHECK("STANDARD_INFO", standard_info, nlink, 
733                   "ALL_INFO",      all_info,      nlink);
734         s1 = fnum_find("BASIC_INFO");
735         if (s1 && is_ipc) {
736                 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
737                         printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
738                         ret = False;
739                 }
740         }
741         s1 = fnum_find("STANDARD_INFO");
742         if (s1 && is_ipc) {
743                 if (s1->standard_info.out.nlink != 1) {
744                         printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
745                         ret = False;
746                 }
747                 if (s1->standard_info.out.delete_pending != 1) {
748                         printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
749                         ret = False;
750                 }
751         }
752         VAL_CHECK("EA_INFO",       ea_info,       ea_size, 
753                   "ALL_INFO",      all_info,      ea_size);
754         if (!is_ipc) {
755                 VAL_CHECK("EA_SIZE",       ea_size,       ea_size, 
756                           "ALL_INFO",      all_info,      ea_size);
757         }
758
759 #define NAME_PATH_CHECK(sname, stype, field) do { \
760         s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
761         if (s1 && s2) { \
762                 VAL_EQUAL(stype, field, stype, field); \
763         } \
764 } while (0)
765
766
767         s1 = fnum_find("INTERNAL_INFORMATION");
768         if (s1) {
769                 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
770         }
771
772         NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
773         NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
774         if (s1 && s2) {
775                 printf("fnum pos = %.0f, fname pos = %.0f\n",
776                        (double)s2->position_information.out.position,
777                        (double)s1->position_information.out.position );
778         }
779         NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
780         NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
781         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
782         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
783
784 #if 0
785         /* these are expected to differ */
786         NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
787 #endif
788
789 #if 0 /* unused */
790 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
791         s1 = fnum_find(sname); \
792         if (s1 && s1->stype.out.tfield != 0) { \
793                 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
794                        #stype, #tfield, \
795                        (uint_t)s1->stype.out.tfield); \
796         } \
797         s1 = fname_find(is_ipc, sname); \
798         if (s1 && s1->stype.out.tfield != 0) { \
799                 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
800                        #stype, #tfield, \
801                        (uint_t)s1->stype.out.tfield); \
802         }} while (0)
803 #endif
804         /* now get a bit fancier .... */
805         
806         /* when we set the delete disposition then the link count should drop
807            to 0 and delete_pending should be 1 */
808         
809
810 done:
811
812         return ret;
813 }
814
815 /* basic testing of all RAW_FILEINFO_* calls 
816    for each call we test that it succeeds, and where possible test 
817    for consistency between the calls. 
818 */
819 BOOL torture_raw_qfileinfo(struct torture_context *torture)
820 {
821         struct smbcli_state *cli;
822         BOOL ret = True;
823         TALLOC_CTX *mem_ctx;
824         int fnum;
825         const char *fname = "\\torture_qfileinfo.txt";
826
827         if (!torture_open_connection(&cli, 0)) {
828                 return False;
829         }
830
831         mem_ctx = talloc_init("torture_qfileinfo");
832
833         fnum = create_complex_file(cli, mem_ctx, fname);
834         if (fnum == -1) {
835                 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
836                 ret = False;
837                 goto done;
838         }
839
840         ret = torture_raw_qfileinfo_internals(torture, mem_ctx, cli->tree, fnum, fname, False /* is_ipc */);
841         
842         smbcli_close(cli->tree, fnum);
843         smbcli_unlink(cli->tree, fname);
844
845 done:
846         torture_close_connection(cli);
847         talloc_free(mem_ctx);
848         return ret;
849 }
850
851 BOOL torture_raw_qfileinfo_pipe(struct torture_context *torture)
852 {
853         TALLOC_CTX *mem_ctx;
854         BOOL ret = True;
855         int fnum;
856         const char *fname = "\\lsass";
857         struct smbcli_state *cli;
858         struct dcerpc_pipe *p;
859         struct smbcli_tree *ipc_tree;
860         NTSTATUS status;
861
862         if (!torture_open_connection(&cli, 0)) {
863                 return False;
864         }
865
866         mem_ctx = talloc_init("torture_qfileinfo_pipe");
867
868         if (!(p = dcerpc_pipe_init(mem_ctx, 
869                                    cli->tree->session->transport->socket->event.ctx))) {
870                 return False;
871         }
872
873         status = dcerpc_pipe_open_smb(p, cli->tree, fname);
874         if (!NT_STATUS_IS_OK(status)) {
875                 d_printf("dcerpc_pipe_open_smb failed: %s\n",
876                          nt_errstr(status));
877                 talloc_free(p);
878                 return False;
879         }
880
881         ipc_tree = dcerpc_smb_tree(p->conn);
882         fnum = dcerpc_smb_fnum(p->conn);
883
884         ret = torture_raw_qfileinfo_internals(torture, mem_ctx, ipc_tree, fnum, fname, True /* is_ipc */);
885         
886         talloc_free(p);
887         return ret;
888 }