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 torture_warning(torture
, "fnum level %s %s",
285 nt_errstr(levels
[i
].fnum_status
));
288 if (!levels
[i
].only_paths
&& !NT_STATUS_EQUAL(levels
[i
].expected_ipc_fnum_status
, levels
[i
].fnum_status
)) {
289 printf("ERROR: fnum level %s failed, expected %s - %s\n",
290 levels
[i
].name
, nt_errstr(levels
[i
].expected_ipc_fnum_status
),
291 nt_errstr(levels
[i
].fnum_status
));
295 if (!levels
[i
].only_paths
&&
296 NT_STATUS_EQUAL(levels
[i
].fnum_status
,
297 NT_STATUS_NOT_SUPPORTED
)) {
298 torture_warning(torture
, "fnum level %s %s",
300 nt_errstr(levels
[i
].fnum_status
));
304 if (!levels
[i
].only_handles
&&
305 NT_STATUS_EQUAL(levels
[i
].fname_status
,
306 NT_STATUS_NOT_SUPPORTED
)) {
307 torture_warning(torture
, "fname level %s %s",
309 nt_errstr(levels
[i
].fname_status
));
313 if (!levels
[i
].only_paths
&& !NT_STATUS_IS_OK(levels
[i
].fnum_status
)) {
314 printf("ERROR: fnum level %s failed - %s\n",
315 levels
[i
].name
, nt_errstr(levels
[i
].fnum_status
));
318 if (!levels
[i
].only_handles
&& !NT_STATUS_IS_OK(levels
[i
].fname_status
)) {
319 printf("ERROR: fname level %s failed - %s\n",
320 levels
[i
].name
, nt_errstr(levels
[i
].fname_status
));
329 printf("%d levels failed\n", count
);
331 torture_fail(torture
, "too many level failures - giving up");
335 /* see if we can do streams */
336 s1
= fnum_find("STREAM_INFO");
337 if (!s1
|| s1
->stream_info
.out
.num_streams
== 0) {
339 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
340 s1
? s1
->stream_info
.out
.num_streams
: -1);
346 /* this code is incredibly repititive but doesn't lend itself to loops, so
347 we use lots of macros to make it less painful */
349 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
350 this code to fail, but we need to check it for completeness */
354 #define ALIAS_CHECK(sname1, sname2) \
356 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
357 if (s1 && s2) { INFO_CHECK } \
358 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
359 if (s1 && s2) { INFO_CHECK } \
360 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
361 if (s1 && s2) { INFO_CHECK } \
365 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
366 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
367 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
368 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
369 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
371 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
375 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
376 VAL_EQUAL(standard_info, size, standard_info, size); \
377 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
378 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
379 VAL_EQUAL(standard_info, directory, standard_info, directory);
381 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
385 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
387 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
391 STR_EQUAL(name_info, fname, name_info, fname);
393 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
397 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
398 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
399 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
400 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
401 VAL_EQUAL(all_info, attrib, all_info, attrib); \
402 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
403 VAL_EQUAL(all_info, size, all_info, size); \
404 VAL_EQUAL(all_info, nlink, all_info, nlink); \
405 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
406 VAL_EQUAL(all_info, directory, all_info, directory); \
407 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
408 STR_EQUAL(all_info, fname, all_info, fname);
410 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
414 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
415 VAL_EQUAL(compression_info, format, compression_info, format); \
416 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
417 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
418 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
420 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
425 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
427 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
430 #define TIME_CHECK_NT(sname, stype, tfield) do { \
431 s1 = fnum_find(sname); \
432 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
433 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
434 nt_time_string(mem_ctx, s1->stype.out.tfield), \
435 nt_time_string(mem_ctx, correct_time)); \
438 s1 = fname_find(is_ipc, sname); \
439 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
440 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
441 nt_time_string(mem_ctx, s1->stype.out.tfield), \
442 nt_time_string(mem_ctx, correct_time)); \
446 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
447 s1 = fnum_find(sname); \
448 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
449 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
450 timestring(mem_ctx, s1->stype.out.tfield), \
451 nt_time_string(mem_ctx, correct_time)); \
454 s1 = fname_find(is_ipc, sname); \
455 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
456 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
457 timestring(mem_ctx, s1->stype.out.tfield), \
458 nt_time_string(mem_ctx, correct_time)); \
463 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
464 s1 = fnum_find(sname); \
465 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
466 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
467 timestring(mem_ctx, s1->stype.out.tfield), \
468 nt_time_string(mem_ctx, correct_time)); \
471 s1 = fname_find(is_ipc, sname); \
472 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
473 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
474 timestring(mem_ctx, s1->stype.out.tfield), \
475 nt_time_string(mem_ctx, correct_time)); \
480 /* now check that all the times that are supposed to be equal are correct */
481 s1
= fnum_find("BASIC_INFO");
482 correct_time
= s1
->basic_info
.out
.create_time
;
483 torture_comment(torture
, "create_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
485 TIME_CHECK_NT ("BASIC_INFO", basic_info
, create_time
);
486 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, create_time
);
487 TIME_CHECK_DOS("GETATTRE", getattre
, create_time
);
488 TIME_CHECK_DOS("STANDARD", standard
, create_time
);
489 TIME_CHECK_DOS("EA_SIZE", ea_size
, create_time
);
490 TIME_CHECK_NT ("ALL_INFO", all_info
, create_time
);
491 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, create_time
);
493 s1
= fnum_find("BASIC_INFO");
494 correct_time
= s1
->basic_info
.out
.access_time
;
495 torture_comment(torture
, "access_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
497 TIME_CHECK_NT ("BASIC_INFO", basic_info
, access_time
);
498 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, access_time
);
499 TIME_CHECK_DOS("GETATTRE", getattre
, access_time
);
500 TIME_CHECK_DOS("STANDARD", standard
, access_time
);
501 TIME_CHECK_DOS("EA_SIZE", ea_size
, access_time
);
502 TIME_CHECK_NT ("ALL_INFO", all_info
, access_time
);
503 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, access_time
);
505 s1
= fnum_find("BASIC_INFO");
506 correct_time
= s1
->basic_info
.out
.write_time
;
507 torture_comment(torture
, "write_time : %s\n", nt_time_string(mem_ctx
, correct_time
));
509 TIME_CHECK_NT ("BASIC_INFO", basic_info
, write_time
);
510 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, write_time
);
511 TIME_CHECK_DOS("GETATTR", getattr
, write_time
);
512 TIME_CHECK_DOS("GETATTRE", getattre
, write_time
);
513 TIME_CHECK_DOS("STANDARD", standard
, write_time
);
514 TIME_CHECK_DOS("EA_SIZE", ea_size
, write_time
);
515 TIME_CHECK_NT ("ALL_INFO", all_info
, write_time
);
516 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, write_time
);
518 s1
= fnum_find("BASIC_INFO");
519 correct_time
= s1
->basic_info
.out
.change_time
;
520 torture_comment(torture
, "change_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
522 TIME_CHECK_NT ("BASIC_INFO", basic_info
, change_time
);
523 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, change_time
);
524 TIME_CHECK_NT ("ALL_INFO", all_info
, change_time
);
525 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, change_time
);
528 #define SIZE_CHECK(sname, stype, tfield) do { \
529 s1 = fnum_find(sname); \
530 if (s1 && s1->stype.out.tfield != correct_size) { \
531 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
532 (unsigned int)s1->stype.out.tfield, \
533 (unsigned int)correct_size); \
536 s1 = fname_find(is_ipc, sname); \
537 if (s1 && s1->stype.out.tfield != correct_size) { \
538 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
539 (unsigned int)s1->stype.out.tfield, \
540 (unsigned int)correct_size); \
544 s1
= fnum_find("STANDARD_INFO");
545 correct_size
= s1
->standard_info
.out
.size
;
546 torture_comment(torture
, "size: %u\n", (unsigned int)correct_size
);
548 SIZE_CHECK("GETATTR", getattr
, size
);
549 SIZE_CHECK("GETATTRE", getattre
, size
);
550 SIZE_CHECK("STANDARD", standard
, size
);
551 SIZE_CHECK("EA_SIZE", ea_size
, size
);
552 SIZE_CHECK("STANDARD_INFO", standard_info
, size
);
553 SIZE_CHECK("STANDARD_INFORMATION", standard_info
, size
);
554 SIZE_CHECK("ALL_INFO", all_info
, size
);
555 SIZE_CHECK("ALL_INFORMATION", all_info
, size
);
556 SIZE_CHECK("COMPRESSION_INFO", compression_info
, compressed_size
);
557 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info
, compressed_size
);
558 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, size
);
560 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].size
);
561 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].size
);
565 s1
= fnum_find("STANDARD_INFO");
566 correct_size
= s1
->standard_info
.out
.alloc_size
;
567 torture_comment(torture
, "alloc_size: %u\n", (unsigned int)correct_size
);
569 SIZE_CHECK("GETATTRE", getattre
, alloc_size
);
570 SIZE_CHECK("STANDARD", standard
, alloc_size
);
571 SIZE_CHECK("EA_SIZE", ea_size
, alloc_size
);
572 SIZE_CHECK("STANDARD_INFO", standard_info
, alloc_size
);
573 SIZE_CHECK("STANDARD_INFORMATION", standard_info
, alloc_size
);
574 SIZE_CHECK("ALL_INFO", all_info
, alloc_size
);
575 SIZE_CHECK("ALL_INFORMATION", all_info
, alloc_size
);
576 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, alloc_size
);
578 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].alloc_size
);
579 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].alloc_size
);
582 #define ATTRIB_CHECK(sname, stype, tfield) do { \
583 s1 = fnum_find(sname); \
584 if (s1 && s1->stype.out.tfield != correct_attrib) { \
585 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
586 (unsigned int)s1->stype.out.tfield, \
587 (unsigned int)correct_attrib); \
590 s1 = fname_find(is_ipc, sname); \
591 if (s1 && s1->stype.out.tfield != correct_attrib) { \
592 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
593 (unsigned int)s1->stype.out.tfield, \
594 (unsigned int)correct_attrib); \
598 s1
= fnum_find("BASIC_INFO");
599 correct_attrib
= s1
->basic_info
.out
.attrib
;
600 torture_comment(torture
, "attrib: 0x%x\n", (unsigned int)correct_attrib
);
602 ATTRIB_CHECK("GETATTR", getattr
, attrib
);
604 ATTRIB_CHECK("GETATTRE", getattre
, attrib
);
605 ATTRIB_CHECK("STANDARD", standard
, attrib
);
606 ATTRIB_CHECK("EA_SIZE", ea_size
, attrib
);
608 ATTRIB_CHECK("BASIC_INFO", basic_info
, attrib
);
609 ATTRIB_CHECK("BASIC_INFORMATION", basic_info
, attrib
);
610 ATTRIB_CHECK("ALL_INFO", all_info
, attrib
);
611 ATTRIB_CHECK("ALL_INFORMATION", all_info
, attrib
);
612 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, attrib
);
613 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, attrib
);
615 correct_name
= fname
;
616 torture_comment(torture
, "name: %s\n", correct_name
);
618 #define NAME_CHECK(sname, stype, tfield, flags) do { \
619 s1 = fnum_find(sname); \
620 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
621 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
622 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
623 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
626 s1 = fname_find(is_ipc, sname); \
627 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
628 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
629 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
630 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
634 NAME_CHECK("NAME_INFO", name_info
, fname
, STR_UNICODE
);
635 NAME_CHECK("NAME_INFORMATION", name_info
, fname
, STR_UNICODE
);
637 /* the ALL_INFO file name is the full path on the filesystem */
638 s1
= fnum_find("ALL_INFO");
639 if (s1
&& !s1
->all_info
.out
.fname
.s
) {
640 torture_fail(torture
, "ALL_INFO didn't give a filename");
642 if (s1
&& s1
->all_info
.out
.fname
.s
) {
643 char *p
= strrchr(s1
->all_info
.out
.fname
.s
, '\\');
645 printf("Not a full path in all_info/fname? - '%s'\n",
646 s1
->all_info
.out
.fname
.s
);
649 if (strcmp_safe(correct_name
, p
) != 0) {
650 printf("incorrect basename in all_info/fname - '%s'\n",
651 s1
->all_info
.out
.fname
.s
);
655 if (wire_bad_flags(&s1
->all_info
.out
.fname
, STR_UNICODE
, tree
->session
->transport
)) {
656 printf("Should not null terminate all_info/fname\n");
661 s1
= fnum_find("ALT_NAME_INFO");
663 correct_name
= s1
->alt_name_info
.out
.fname
.s
;
664 torture_comment(torture
, "alt_name: %s\n", correct_name
);
666 NAME_CHECK("ALT_NAME_INFO", alt_name_info
, fname
, STR_UNICODE
);
667 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info
, fname
, STR_UNICODE
);
669 /* and make sure we can open by alternate name */
670 smbcli_close(tree
, fnum
);
671 fnum
= smbcli_nt_create_full(tree
, correct_name
, 0,
673 FILE_ATTRIBUTE_NORMAL
,
674 NTCREATEX_SHARE_ACCESS_DELETE
|
675 NTCREATEX_SHARE_ACCESS_READ
|
676 NTCREATEX_SHARE_ACCESS_WRITE
,
677 NTCREATEX_DISP_OVERWRITE_IF
,
680 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree
));
685 correct_name
= "::$DATA";
686 torture_comment(torture
, "stream_name: %s\n", correct_name
);
688 NAME_CHECK("STREAM_INFO", stream_info
, streams
[0].stream_name
, STR_UNICODE
);
689 NAME_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].stream_name
, STR_UNICODE
);
693 /* make sure the EAs look right */
694 s1
= fnum_find("ALL_EAS");
695 s2
= fnum_find("ALL_INFO");
697 for (i
=0;i
<s1
->all_eas
.out
.num_eas
;i
++) {
698 printf(" flags=%d %s=%*.*s\n",
699 s1
->all_eas
.out
.eas
[i
].flags
,
700 s1
->all_eas
.out
.eas
[i
].name
.s
,
701 (int)s1
->all_eas
.out
.eas
[i
].value
.length
,
702 (int)s1
->all_eas
.out
.eas
[i
].value
.length
,
703 s1
->all_eas
.out
.eas
[i
].value
.data
);
707 if (s1
->all_eas
.out
.num_eas
== 0) {
708 if (s2
->all_info
.out
.ea_size
!= 0) {
709 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
710 s2
->all_info
.out
.ea_size
);
713 if (s2
->all_info
.out
.ea_size
!=
714 ea_list_size(s1
->all_eas
.out
.num_eas
, s1
->all_eas
.out
.eas
)) {
715 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
716 (int)ea_list_size(s1
->all_eas
.out
.num_eas
, s1
->all_eas
.out
.eas
),
717 (int)s2
->all_info
.out
.ea_size
);
721 s2
= fname_find(is_ipc
, "ALL_EAS");
723 VAL_EQUAL(all_eas
, num_eas
, all_eas
, num_eas
);
724 for (i
=0;i
<s1
->all_eas
.out
.num_eas
;i
++) {
725 VAL_EQUAL(all_eas
, eas
[i
].flags
, all_eas
, eas
[i
].flags
);
726 STR_EQUAL(all_eas
, eas
[i
].name
, all_eas
, eas
[i
].name
);
727 VAL_EQUAL(all_eas
, eas
[i
].value
.length
, all_eas
, eas
[i
].value
.length
);
731 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
732 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
733 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
734 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
735 #stype1, #tfield1, #stype2, #tfield2, \
736 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
739 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
740 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
741 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
742 #stype1, #tfield1, #stype2, #tfield2, \
743 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
746 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
747 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
748 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
749 #stype1, #tfield1, #stype2, #tfield2, \
750 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
753 s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
754 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
755 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
756 #stype1, #tfield1, #stype2, #tfield2, \
757 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
761 VAL_CHECK("STANDARD_INFO", standard_info
, delete_pending
,
762 "ALL_INFO", all_info
, delete_pending
);
763 VAL_CHECK("STANDARD_INFO", standard_info
, directory
,
764 "ALL_INFO", all_info
, directory
);
765 VAL_CHECK("STANDARD_INFO", standard_info
, nlink
,
766 "ALL_INFO", all_info
, nlink
);
767 s1
= fnum_find("BASIC_INFO");
769 if (s1
->basic_info
.out
.attrib
!= FILE_ATTRIBUTE_NORMAL
) {
770 printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__
, s1
->basic_info
.out
.attrib
, FILE_ATTRIBUTE_NORMAL
);
774 s1
= fnum_find("STANDARD_INFO");
776 if (s1
->standard_info
.out
.nlink
!= 1) {
777 printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__
, s1
->standard_info
.out
.nlink
);
780 if (s1
->standard_info
.out
.delete_pending
!= 1) {
781 printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__
, s1
->standard_info
.out
.delete_pending
);
785 VAL_CHECK("EA_INFO", ea_info
, ea_size
,
786 "ALL_INFO", all_info
, ea_size
);
788 VAL_CHECK("EA_SIZE", ea_size
, ea_size
,
789 "ALL_INFO", all_info
, ea_size
);
792 #define NAME_PATH_CHECK(sname, stype, field) do { \
793 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
795 VAL_EQUAL(stype, field, stype, field); \
800 s1
= fnum_find("INTERNAL_INFORMATION");
802 torture_comment(torture
, "file_id=%.0f\n", (double)s1
->internal_information
.out
.file_id
);
805 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information
, file_id
);
806 NAME_PATH_CHECK("POSITION_INFORMATION", position_information
, position
);
808 printf("fnum pos = %.0f, fname pos = %.0f\n",
809 (double)s2
->position_information
.out
.position
,
810 (double)s1
->position_information
.out
.position
);
812 NAME_PATH_CHECK("MODE_INFORMATION", mode_information
, mode
);
813 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information
, alignment_requirement
);
814 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, attrib
);
815 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, reparse_tag
);
818 /* these are expected to differ */
819 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information
, access_flags
);
823 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
824 s1 = fnum_find(sname); \
825 if (s1 && s1->stype.out.tfield != 0) { \
826 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
828 (unsigned int)s1->stype.out.tfield); \
830 s1 = fname_find(is_ipc, sname); \
831 if (s1 && s1->stype.out.tfield != 0) { \
832 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
834 (unsigned int)s1->stype.out.tfield); \
837 /* now get a bit fancier .... */
839 /* when we set the delete disposition then the link count should drop
840 to 0 and delete_pending should be 1 */
845 /* basic testing of all RAW_FILEINFO_* calls
846 for each call we test that it succeeds, and where possible test
847 for consistency between the calls.
849 bool torture_raw_qfileinfo(struct torture_context
*torture
,
850 struct smbcli_state
*cli
)
854 const char *fname
= "\\torture_qfileinfo.txt";
856 fnum
= create_complex_file(cli
, torture
, fname
);
858 printf("ERROR: open of %s failed (%s)\n", fname
, smbcli_errstr(cli
->tree
));
862 ret
= torture_raw_qfileinfo_internals(torture
, torture
, cli
->tree
, fnum
, fname
, false /* is_ipc */);
864 smbcli_close(cli
->tree
, fnum
);
865 smbcli_unlink(cli
->tree
, fname
);
870 bool torture_raw_qfileinfo_pipe(struct torture_context
*torture
,
871 struct smbcli_state
*cli
)
875 const char *fname
= "\\lsass";
876 struct dcerpc_pipe
*p
;
877 struct smbcli_tree
*ipc_tree
;
880 if (!(p
= dcerpc_pipe_init(torture
, cli
->tree
->session
->transport
->socket
->event
.ctx
))) {
884 status
= dcerpc_pipe_open_smb(p
, cli
->tree
, fname
);
885 torture_assert_ntstatus_ok(torture
, status
, "dcerpc_pipe_open_smb failed");
887 ipc_tree
= dcerpc_smb_tree(p
->conn
);
888 fnum
= dcerpc_smb_fnum(p
->conn
);
890 ret
= torture_raw_qfileinfo_internals(torture
, torture
, ipc_tree
, fnum
, fname
, true /* is_ipc */);