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