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