Merge commit 'release-4-0-0alpha1' into v4-0-test
[kai/samba.git] / source / torture / raw / qfileinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3    RAW_FILEINFO_* individual test suite
4    Copyright (C) Andrew Tridgell 2003
5    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 #include "torture/raw/proto.h"
29
30 static struct {
31         const char *name;
32         enum smb_fileinfo_level level;
33         uint_t only_paths:1;
34         uint_t only_handles:1;
35         uint32_t capability_mask;
36         uint_t 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;
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, (uint_t)s1->n1.out.v1, \
187                #n2, #v2, (uint_t)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                (uint_t)s1->n1.out.v1, \
216                (uint_t)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 && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
270                                 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", 
271                                        levels[i].name, nt_errstr(levels[i].fname_status));
272                                 count++;
273                         }
274                         if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
275                                 printf("ERROR: fnum level %s failed, expected %s - %s\n", 
276                                        levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), 
277                                        nt_errstr(levels[i].fnum_status));
278                                 count++;
279                         }
280                 } else {
281                         if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
282                                 printf("ERROR: fnum level %s failed - %s\n", 
283                                        levels[i].name, nt_errstr(levels[i].fnum_status));
284                                 count++;
285                         }
286                         if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
287                                 printf("ERROR: fname level %s failed - %s\n", 
288                                        levels[i].name, nt_errstr(levels[i].fname_status));
289                                 count++;
290                         }
291                 }
292                 
293         }
294
295         if (count != 0) {
296                 ret = false;
297                 printf("%d levels failed\n", count);
298                 if (count > 35) {
299                         torture_fail(torture, "too many level failures - giving up");
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         torture_comment(torture, "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         torture_comment(torture, "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         torture_comment(torture, "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         torture_comment(torture, "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         torture_comment(torture, "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         torture_comment(torture, "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         torture_comment(torture, "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         torture_comment(torture, "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                 torture_fail(torture, "ALL_INFO didn't give a filename");
609         }
610         if (s1 && s1->all_info.out.fname.s) {
611                 char *p = strrchr(s1->all_info.out.fname.s, '\\');
612                 if (!p) {
613                         printf("Not a full path in all_info/fname? - '%s'\n", 
614                                s1->all_info.out.fname.s);
615                         ret = false;
616                 } else {
617                         if (strcmp_safe(correct_name, p) != 0) {
618                                 printf("incorrect basename in all_info/fname - '%s'\n",
619                                        s1->all_info.out.fname.s);
620                                 ret = false;
621                         }
622                 }
623                 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
624                         printf("Should not null terminate all_info/fname\n");
625                         ret = false;
626                 }
627         }
628
629         s1 = fnum_find("ALT_NAME_INFO");
630         if (s1) {
631                 correct_name = s1->alt_name_info.out.fname.s;
632                 torture_comment(torture, "alt_name: %s\n", correct_name);
633                 
634                 NAME_CHECK("ALT_NAME_INFO",        alt_name_info, fname, STR_UNICODE);
635                 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
636                 
637                 /* and make sure we can open by alternate name */
638                 smbcli_close(tree, fnum);
639                 fnum = smbcli_nt_create_full(tree, correct_name, 0, 
640                                              SEC_RIGHTS_FILE_ALL,
641                                              FILE_ATTRIBUTE_NORMAL,
642                                              NTCREATEX_SHARE_ACCESS_DELETE|
643                                              NTCREATEX_SHARE_ACCESS_READ|
644                                              NTCREATEX_SHARE_ACCESS_WRITE, 
645                                              NTCREATEX_DISP_OVERWRITE_IF, 
646                                              0, 0);
647                 if (fnum == -1) {
648                         printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
649                         ret = false;
650                 }
651                 
652                 if (!skip_streams) {
653                         correct_name = "::$DATA";
654                         torture_comment(torture, "stream_name: %s\n", correct_name);
655                         
656                         NAME_CHECK("STREAM_INFO",        stream_info, streams[0].stream_name, STR_UNICODE);
657                         NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
658                 }
659         }
660                 
661         /* make sure the EAs look right */
662         s1 = fnum_find("ALL_EAS");
663         s2 = fnum_find("ALL_INFO");
664         if (s1) {
665                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
666                         printf("  flags=%d %s=%*.*s\n", 
667                                s1->all_eas.out.eas[i].flags,
668                                s1->all_eas.out.eas[i].name.s,
669                                (int)s1->all_eas.out.eas[i].value.length,
670                                (int)s1->all_eas.out.eas[i].value.length,
671                                s1->all_eas.out.eas[i].value.data);
672                 }
673         }
674         if (s1 && s2) {
675                 if (s1->all_eas.out.num_eas == 0) {
676                         if (s2->all_info.out.ea_size != 0) {
677                                 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
678                                        s2->all_info.out.ea_size);
679                         }
680                 } else {
681                         if (s2->all_info.out.ea_size != 
682                             ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
683                                 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
684                                        (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
685                                        (int)s2->all_info.out.ea_size);
686                         }
687                 }
688         }
689         s2 = fname_find(is_ipc, "ALL_EAS");
690         if (s2) {
691                 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
692                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
693                         VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
694                         STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
695                         VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
696                 }
697         }
698
699 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
700         s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
701         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
702                 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
703                        #stype1, #tfield1, #stype2, #tfield2,  \
704                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
705                 ret = false; \
706         } \
707         s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
708         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
709                 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
710                        #stype1, #tfield1, #stype2, #tfield2,  \
711                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
712                 ret = false; \
713         } \
714         s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
715         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
716                 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
717                        #stype1, #tfield1, #stype2, #tfield2,  \
718                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
719                 ret = false; \
720         } \
721         s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
722         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
723                 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
724                        #stype1, #tfield1, #stype2, #tfield2,  \
725                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
726                 ret = false; \
727         }} while (0)
728
729         VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, 
730                   "ALL_INFO",      all_info,      delete_pending);
731         VAL_CHECK("STANDARD_INFO", standard_info, directory, 
732                   "ALL_INFO",      all_info,      directory);
733         VAL_CHECK("STANDARD_INFO", standard_info, nlink, 
734                   "ALL_INFO",      all_info,      nlink);
735         s1 = fnum_find("BASIC_INFO");
736         if (s1 && is_ipc) {
737                 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
738                         printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
739                         ret = false;
740                 }
741         }
742         s1 = fnum_find("STANDARD_INFO");
743         if (s1 && is_ipc) {
744                 if (s1->standard_info.out.nlink != 1) {
745                         printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
746                         ret = false;
747                 }
748                 if (s1->standard_info.out.delete_pending != 1) {
749                         printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
750                         ret = false;
751                 }
752         }
753         VAL_CHECK("EA_INFO",       ea_info,       ea_size, 
754                   "ALL_INFO",      all_info,      ea_size);
755         if (!is_ipc) {
756                 VAL_CHECK("EA_SIZE",       ea_size,       ea_size, 
757                           "ALL_INFO",      all_info,      ea_size);
758         }
759
760 #define NAME_PATH_CHECK(sname, stype, field) do { \
761         s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
762         if (s1 && s2) { \
763                 VAL_EQUAL(stype, field, stype, field); \
764         } \
765 } while (0)
766
767
768         s1 = fnum_find("INTERNAL_INFORMATION");
769         if (s1) {
770                 torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id);
771         }
772
773         NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
774         NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
775         if (s1 && s2) {
776                 printf("fnum pos = %.0f, fname pos = %.0f\n",
777                        (double)s2->position_information.out.position,
778                        (double)s1->position_information.out.position );
779         }
780         NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
781         NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
782         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
783         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
784
785 #if 0
786         /* these are expected to differ */
787         NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
788 #endif
789
790 #if 0 /* unused */
791 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
792         s1 = fnum_find(sname); \
793         if (s1 && s1->stype.out.tfield != 0) { \
794                 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
795                        #stype, #tfield, \
796                        (uint_t)s1->stype.out.tfield); \
797         } \
798         s1 = fname_find(is_ipc, sname); \
799         if (s1 && s1->stype.out.tfield != 0) { \
800                 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
801                        #stype, #tfield, \
802                        (uint_t)s1->stype.out.tfield); \
803         }} while (0)
804 #endif
805         /* now get a bit fancier .... */
806         
807         /* when we set the delete disposition then the link count should drop
808            to 0 and delete_pending should be 1 */
809         
810         return ret;
811 }
812
813 /* basic testing of all RAW_FILEINFO_* calls 
814    for each call we test that it succeeds, and where possible test 
815    for consistency between the calls. 
816 */
817 bool torture_raw_qfileinfo(struct torture_context *torture, 
818                                                    struct smbcli_state *cli)
819 {
820         int fnum;
821         bool ret;
822         const char *fname = "\\torture_qfileinfo.txt";
823
824         fnum = create_complex_file(cli, torture, fname);
825         if (fnum == -1) {
826                 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
827                 return false;
828         }
829
830         ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */);
831         
832         smbcli_close(cli->tree, fnum);
833         smbcli_unlink(cli->tree, fname);
834
835         return ret;
836 }
837
838 bool torture_raw_qfileinfo_pipe(struct torture_context *torture, 
839                                 struct smbcli_state *cli)
840 {
841         bool ret = true;
842         int fnum;
843         const char *fname = "\\lsass";
844         struct dcerpc_pipe *p;
845         struct smbcli_tree *ipc_tree;
846         NTSTATUS status;
847
848         if (!(p = dcerpc_pipe_init(torture, cli->tree->session->transport->socket->event.ctx))) {
849                 return false;
850         }
851
852         status = dcerpc_pipe_open_smb(p, cli->tree, fname);
853         torture_assert_ntstatus_ok(torture, status, "dcerpc_pipe_open_smb failed");
854
855         ipc_tree = dcerpc_smb_tree(p->conn);
856         fnum = dcerpc_smb_fnum(p->conn);
857
858         ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, true /* is_ipc */);
859         
860         talloc_free(p);
861         return ret;
862 }