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
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.
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.
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/>.
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"
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
;
41 .level
= RAW_FILEINFO_GETATTR
,
44 .expected_ipc_access_denied
= 1},
46 .level
= RAW_FILEINFO_GETATTRE
,
50 .level
= RAW_FILEINFO_STANDARD
, },
52 .level
= RAW_FILEINFO_EA_SIZE
},
54 .level
= RAW_FILEINFO_ALL_EAS
,
55 .expected_ipc_fnum_status
= NT_STATUS_ACCESS_DENIED
,
57 { .name
="IS_NAME_VALID",
58 .level
= RAW_FILEINFO_IS_NAME_VALID
,
61 { .name
="BASIC_INFO",
62 .level
= RAW_FILEINFO_BASIC_INFO
},
63 { .name
="STANDARD_INFO",
64 .level
= RAW_FILEINFO_STANDARD_INFO
},
66 .level
= RAW_FILEINFO_EA_INFO
},
68 .level
= RAW_FILEINFO_NAME_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
75 { .name
="STREAM_INFO",
76 .level
= RAW_FILEINFO_STREAM_INFO
,
77 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
79 { .name
="COMPRESSION_INFO",
80 .level
= RAW_FILEINFO_COMPRESSION_INFO
,
81 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
83 { .name
="UNIX_BASIC_INFO",
84 .level
= RAW_FILEINFO_UNIX_BASIC
,
87 .capability_mask
= CAP_UNIX
},
88 { .name
="UNIX_LINK_INFO",
89 .level
= RAW_FILEINFO_UNIX_LINK
,
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
117 { .name
="STREAM_INFORMATION",
118 .level
= RAW_FILEINFO_STREAM_INFORMATION
,
119 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
121 { .name
= "COMPRESSION_INFORMATION",
122 .level
= RAW_FILEINFO_COMPRESSION_INFORMATION
,
123 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
125 { .name
="NETWORK_OPEN_INFORMATION",
126 .level
= RAW_FILEINFO_NETWORK_OPEN_INFORMATION
,
127 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
129 { .name
= "ATTRIBUTE_TAG_INFORMATION",
130 .level
= RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
,
131 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
137 compare a dos time (2 second resolution) to a nt time
139 static int dos_nt_time_cmp(time_t t
, NTTIME nt
)
141 time_t t2
= nt_time_to_unix(nt
);
142 if (abs(t2
- t
) <= 2) return 0;
143 return t2
> t
? 1 : -1;
148 find a level in the levels[] table
150 static union smb_fileinfo
*fnum_find(const char *name
)
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
;
164 find a level in the levels[] table
166 static union smb_fileinfo
*fname_find(bool is_ipc
, const char *name
)
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
;
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__); \
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__); \
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", \
204 __FILE__, __LINE__); \
208 /* used to find hints on unknown values - and to make sure
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", \
214 (unsigned int)s1->n1.out.v1, \
215 (unsigned int)s1->n1.out.v1, \
216 __FILE__, __LINE__); \
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.
225 static bool torture_raw_qfileinfo_internals(struct torture_context
*torture
,
227 struct smbcli_tree
*tree
,
228 int fnum
, const char *fname
,
234 union smb_fileinfo
*s1
, *s2
;
236 uint64_t correct_size
;
237 uint32_t correct_attrib
;
238 const char *correct_name
;
239 bool skip_streams
= false;
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
);
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
);
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
) {
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",
273 nt_errstr(levels
[i
].fname_status
));
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
));
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",
287 nt_errstr(levels
[i
].fnum_status
));
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
));
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",
304 nt_errstr(levels
[i
].fnum_status
));
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",
315 nt_errstr(levels
[i
].fname_status
));
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
));
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
));
335 printf("%d levels failed\n", count
);
337 torture_fail(torture
, "too many level failures - giving up");
341 /* see if we can do streams */
342 s1
= fnum_find("STREAM_INFO");
343 if (!s1
|| s1
->stream_info
.out
.num_streams
== 0) {
345 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
346 s1
? s1
->stream_info
.out
.num_streams
: -1);
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 */
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 */
360 #define ALIAS_CHECK(sname1, sname2) \
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 } \
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);
377 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
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);
387 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
391 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
393 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
397 STR_EQUAL(name_info, fname, name_info, fname);
399 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
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);
416 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
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);
426 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
431 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
433 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
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)); \
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)); \
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)); \
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)); \
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)); \
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)); \
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
));
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
);
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
));
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
);
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
));
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
);
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
));
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
);
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); \
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); \
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
);
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
);
566 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].size
);
567 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].size
);
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
);
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
);
584 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].alloc_size
);
585 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].alloc_size
);
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); \
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); \
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
);
608 ATTRIB_CHECK("GETATTR", getattr
, attrib
);
610 ATTRIB_CHECK("GETATTRE", getattre
, attrib
);
611 ATTRIB_CHECK("STANDARD", standard
, attrib
);
612 ATTRIB_CHECK("EA_SIZE", ea_size
, attrib
);
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
);
621 correct_name
= fname
;
622 torture_comment(torture
, "name: %s\n", correct_name
);
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); \
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); \
640 NAME_CHECK("NAME_INFO", name_info
, fname
, STR_UNICODE
);
641 NAME_CHECK("NAME_INFORMATION", name_info
, fname
, STR_UNICODE
);
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");
648 if (s1
&& s1
->all_info
.out
.fname
.s
) {
649 char *p
= strrchr(s1
->all_info
.out
.fname
.s
, '\\');
651 printf("Not a full path in all_info/fname? - '%s'\n",
652 s1
->all_info
.out
.fname
.s
);
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
);
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");
667 s1
= fnum_find("ALT_NAME_INFO");
669 correct_name
= s1
->alt_name_info
.out
.fname
.s
;
673 torture_comment(torture
, "no alternate name information\n");
675 torture_comment(torture
, "alt_name: %s\n", correct_name
);
677 NAME_CHECK("ALT_NAME_INFO", alt_name_info
, fname
, STR_UNICODE
);
678 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info
, fname
, STR_UNICODE
);
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,
684 FILE_ATTRIBUTE_NORMAL
,
685 NTCREATEX_SHARE_ACCESS_DELETE
|
686 NTCREATEX_SHARE_ACCESS_READ
|
687 NTCREATEX_SHARE_ACCESS_WRITE
,
688 NTCREATEX_DISP_OVERWRITE_IF
,
691 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree
));
696 correct_name
= "::$DATA";
697 torture_comment(torture
, "stream_name: %s\n", correct_name
);
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
);
704 /* make sure the EAs look right */
705 s1
= fnum_find("ALL_EAS");
706 s2
= fnum_find("ALL_INFO");
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
);
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
);
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
);
732 s2
= fname_find(is_ipc
, "ALL_EAS");
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
);
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); \
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); \
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); \
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); \
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");
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
);
785 s1
= fnum_find("STANDARD_INFO");
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
);
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
);
796 VAL_CHECK("EA_INFO", ea_info
, ea_size
,
797 "ALL_INFO", all_info
, ea_size
);
799 VAL_CHECK("EA_SIZE", ea_size
, ea_size
,
800 "ALL_INFO", all_info
, ea_size
);
803 #define NAME_PATH_CHECK(sname, stype, field) do { \
804 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
806 VAL_EQUAL(stype, field, stype, field); \
811 s1
= fnum_find("INTERNAL_INFORMATION");
813 torture_comment(torture
, "file_id=%.0f\n", (double)s1
->internal_information
.out
.file_id
);
816 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information
, file_id
);
817 NAME_PATH_CHECK("POSITION_INFORMATION", position_information
, position
);
819 printf("fnum pos = %.0f, fname pos = %.0f\n",
820 (double)s2
->position_information
.out
.position
,
821 (double)s1
->position_information
.out
.position
);
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
);
829 /* these are expected to differ */
830 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information
, access_flags
);
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__, \
839 (unsigned int)s1->stype.out.tfield); \
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__, \
845 (unsigned int)s1->stype.out.tfield); \
848 /* now get a bit fancier .... */
850 /* when we set the delete disposition then the link count should drop
851 to 0 and delete_pending should be 1 */
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.
860 bool torture_raw_qfileinfo(struct torture_context
*torture
,
861 struct smbcli_state
*cli
)
865 const char *fname
= "\\torture_qfileinfo.txt";
867 fnum
= create_complex_file(cli
, torture
, fname
);
869 printf("ERROR: open of %s failed (%s)\n", fname
, smbcli_errstr(cli
->tree
));
873 ret
= torture_raw_qfileinfo_internals(torture
, torture
, cli
->tree
, fnum
, fname
, false /* is_ipc */);
875 smbcli_close(cli
->tree
, fnum
);
876 smbcli_unlink(cli
->tree
, fname
);
881 bool torture_raw_qfileinfo_pipe(struct torture_context
*torture
,
882 struct smbcli_state
*cli
)
886 const char *fname
= "\\lsass";
887 struct dcerpc_pipe
*p
;
888 struct smbcli_tree
*ipc_tree
;
891 if (!(p
= dcerpc_pipe_init(torture
, cli
->tree
->session
->transport
->socket
->event
.ctx
))) {
895 status
= dcerpc_pipe_open_smb(p
, cli
->tree
, fname
);
896 torture_assert_ntstatus_ok(torture
, status
, "dcerpc_pipe_open_smb failed");
898 ipc_tree
= dcerpc_smb_tree(p
->conn
);
899 fnum
= dcerpc_smb_fnum(p
->conn
);
901 ret
= torture_raw_qfileinfo_internals(torture
, torture
, ipc_tree
, fnum
, fname
, true /* is_ipc */);