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