smbtorture: Don't crash RAW-QFILEINFO if there's no alternate name.
[nivanova/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         }
671
672         if (!correct_name) {
673                 torture_comment(torture, "no alternate name information\n");
674         } else {
675                 torture_comment(torture, "alt_name: %s\n", correct_name);
676                 
677                 NAME_CHECK("ALT_NAME_INFO",        alt_name_info, fname, STR_UNICODE);
678                 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
679                 
680                 /* and make sure we can open by alternate name */
681                 smbcli_close(tree, fnum);
682                 fnum = smbcli_nt_create_full(tree, correct_name, 0, 
683                                              SEC_RIGHTS_FILE_ALL,
684                                              FILE_ATTRIBUTE_NORMAL,
685                                              NTCREATEX_SHARE_ACCESS_DELETE|
686                                              NTCREATEX_SHARE_ACCESS_READ|
687                                              NTCREATEX_SHARE_ACCESS_WRITE, 
688                                              NTCREATEX_DISP_OVERWRITE_IF, 
689                                              0, 0);
690                 if (fnum == -1) {
691                         printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
692                         ret = false;
693                 }
694                 
695                 if (!skip_streams) {
696                         correct_name = "::$DATA";
697                         torture_comment(torture, "stream_name: %s\n", correct_name);
698                         
699                         NAME_CHECK("STREAM_INFO",        stream_info, streams[0].stream_name, STR_UNICODE);
700                         NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
701                 }
702         }
703                 
704         /* make sure the EAs look right */
705         s1 = fnum_find("ALL_EAS");
706         s2 = fnum_find("ALL_INFO");
707         if (s1) {
708                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
709                         printf("  flags=%d %s=%*.*s\n", 
710                                s1->all_eas.out.eas[i].flags,
711                                s1->all_eas.out.eas[i].name.s,
712                                (int)s1->all_eas.out.eas[i].value.length,
713                                (int)s1->all_eas.out.eas[i].value.length,
714                                s1->all_eas.out.eas[i].value.data);
715                 }
716         }
717         if (s1 && s2) {
718                 if (s1->all_eas.out.num_eas == 0) {
719                         if (s2->all_info.out.ea_size != 0) {
720                                 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
721                                        s2->all_info.out.ea_size);
722                         }
723                 } else {
724                         if (s2->all_info.out.ea_size != 
725                             ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
726                                 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
727                                        (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
728                                        (int)s2->all_info.out.ea_size);
729                         }
730                 }
731         }
732         s2 = fname_find(is_ipc, "ALL_EAS");
733         if (s2) {
734                 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
735                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
736                         VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
737                         STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
738                         VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
739                 }
740         }
741
742 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
743         s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
744         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
745                 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
746                        #stype1, #tfield1, #stype2, #tfield2,  \
747                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
748                 ret = false; \
749         } \
750         s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
751         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
752                 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
753                        #stype1, #tfield1, #stype2, #tfield2,  \
754                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
755                 ret = false; \
756         } \
757         s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
758         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
759                 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
760                        #stype1, #tfield1, #stype2, #tfield2,  \
761                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
762                 ret = false; \
763         } \
764         s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
765         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
766                 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
767                        #stype1, #tfield1, #stype2, #tfield2,  \
768                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
769                 ret = false; \
770         }} while (0)
771
772         VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, 
773                   "ALL_INFO",      all_info,      delete_pending);
774         VAL_CHECK("STANDARD_INFO", standard_info, directory, 
775                   "ALL_INFO",      all_info,      directory);
776         VAL_CHECK("STANDARD_INFO", standard_info, nlink, 
777                   "ALL_INFO",      all_info,      nlink);
778         s1 = fnum_find("BASIC_INFO");
779         if (s1 && is_ipc) {
780                 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
781                         printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
782                         ret = false;
783                 }
784         }
785         s1 = fnum_find("STANDARD_INFO");
786         if (s1 && is_ipc) {
787                 if (s1->standard_info.out.nlink != 1) {
788                         printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
789                         ret = false;
790                 }
791                 if (s1->standard_info.out.delete_pending != 1) {
792                         printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
793                         ret = false;
794                 }
795         }
796         VAL_CHECK("EA_INFO",       ea_info,       ea_size, 
797                   "ALL_INFO",      all_info,      ea_size);
798         if (!is_ipc) {
799                 VAL_CHECK("EA_SIZE",       ea_size,       ea_size, 
800                           "ALL_INFO",      all_info,      ea_size);
801         }
802
803 #define NAME_PATH_CHECK(sname, stype, field) do { \
804         s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
805         if (s1 && s2) { \
806                 VAL_EQUAL(stype, field, stype, field); \
807         } \
808 } while (0)
809
810
811         s1 = fnum_find("INTERNAL_INFORMATION");
812         if (s1) {
813                 torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id);
814         }
815
816         NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
817         NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
818         if (s1 && s2) {
819                 printf("fnum pos = %.0f, fname pos = %.0f\n",
820                        (double)s2->position_information.out.position,
821                        (double)s1->position_information.out.position );
822         }
823         NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
824         NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
825         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
826         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
827
828 #if 0
829         /* these are expected to differ */
830         NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
831 #endif
832
833 #if 0 /* unused */
834 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
835         s1 = fnum_find(sname); \
836         if (s1 && s1->stype.out.tfield != 0) { \
837                 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
838                        #stype, #tfield, \
839                        (unsigned int)s1->stype.out.tfield); \
840         } \
841         s1 = fname_find(is_ipc, sname); \
842         if (s1 && s1->stype.out.tfield != 0) { \
843                 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
844                        #stype, #tfield, \
845                        (unsigned int)s1->stype.out.tfield); \
846         }} while (0)
847 #endif
848         /* now get a bit fancier .... */
849         
850         /* when we set the delete disposition then the link count should drop
851            to 0 and delete_pending should be 1 */
852         
853         return ret;
854 }
855
856 /* basic testing of all RAW_FILEINFO_* calls 
857    for each call we test that it succeeds, and where possible test 
858    for consistency between the calls. 
859 */
860 bool torture_raw_qfileinfo(struct torture_context *torture, 
861                                                    struct smbcli_state *cli)
862 {
863         int fnum;
864         bool ret;
865         const char *fname = "\\torture_qfileinfo.txt";
866
867         fnum = create_complex_file(cli, torture, fname);
868         if (fnum == -1) {
869                 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
870                 return false;
871         }
872
873         ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */);
874         
875         smbcli_close(cli->tree, fnum);
876         smbcli_unlink(cli->tree, fname);
877
878         return ret;
879 }
880
881 bool torture_raw_qfileinfo_pipe(struct torture_context *torture, 
882                                 struct smbcli_state *cli)
883 {
884         bool ret = true;
885         int fnum;
886         const char *fname = "\\lsass";
887         struct dcerpc_pipe *p;
888         struct smbcli_tree *ipc_tree;
889         NTSTATUS status;
890
891         if (!(p = dcerpc_pipe_init(torture, cli->tree->session->transport->socket->event.ctx))) {
892                 return false;
893         }
894
895         status = dcerpc_pipe_open_smb(p, cli->tree, fname);
896         torture_assert_ntstatus_ok(torture, status, "dcerpc_pipe_open_smb failed");
897
898         ipc_tree = dcerpc_smb_tree(p->conn);
899         fnum = dcerpc_smb_fnum(p->conn);
900
901         ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, true /* is_ipc */);
902         
903         talloc_free(p);
904         return ret;
905 }