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 "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "torture/rpc/rpc.h"
29 #include "torture/raw/proto.h"
30 #include "param/param.h"
34 enum smb_fileinfo_level level
;
36 uint_t only_handles
:1;
37 uint32_t capability_mask
;
38 uint_t expected_ipc_access_denied
:1;
39 NTSTATUS expected_ipc_fnum_status
;
40 NTSTATUS fnum_status
, fname_status
;
41 union smb_fileinfo fnum_finfo
, fname_finfo
;
44 .level
= RAW_FILEINFO_GETATTR
,
47 .expected_ipc_access_denied
= 1},
49 .level
= RAW_FILEINFO_GETATTRE
,
53 .level
= RAW_FILEINFO_STANDARD
, },
55 .level
= RAW_FILEINFO_EA_SIZE
},
57 .level
= RAW_FILEINFO_ALL_EAS
,
58 .expected_ipc_fnum_status
= NT_STATUS_ACCESS_DENIED
,
60 { .name
="IS_NAME_VALID",
61 .level
= RAW_FILEINFO_IS_NAME_VALID
,
64 { .name
="BASIC_INFO",
65 .level
= RAW_FILEINFO_BASIC_INFO
},
66 { .name
="STANDARD_INFO",
67 .level
= RAW_FILEINFO_STANDARD_INFO
},
69 .level
= RAW_FILEINFO_EA_INFO
},
71 .level
= RAW_FILEINFO_NAME_INFO
},
73 .level
= RAW_FILEINFO_ALL_INFO
},
74 { .name
="ALT_NAME_INFO",
75 .level
= RAW_FILEINFO_ALT_NAME_INFO
,
76 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
78 { .name
="STREAM_INFO",
79 .level
= RAW_FILEINFO_STREAM_INFO
,
80 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
82 { .name
="COMPRESSION_INFO",
83 .level
= RAW_FILEINFO_COMPRESSION_INFO
,
84 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
86 { .name
="UNIX_BASIC_INFO",
87 .level
= RAW_FILEINFO_UNIX_BASIC
,
90 .capability_mask
= CAP_UNIX
},
91 { .name
="UNIX_LINK_INFO",
92 .level
= RAW_FILEINFO_UNIX_LINK
,
95 .capability_mask
= CAP_UNIX
},
96 { .name
="BASIC_INFORMATION",
97 .level
= RAW_FILEINFO_BASIC_INFORMATION
},
98 { .name
="STANDARD_INFORMATION",
99 .level
= RAW_FILEINFO_STANDARD_INFORMATION
},
100 { .name
="INTERNAL_INFORMATION",
101 .level
= RAW_FILEINFO_INTERNAL_INFORMATION
},
102 { .name
="EA_INFORMATION",
103 .level
= RAW_FILEINFO_EA_INFORMATION
},
104 { .name
= "ACCESS_INFORMATION",
105 .level
= RAW_FILEINFO_ACCESS_INFORMATION
},
106 { .name
= "NAME_INFORMATION",
107 .level
= RAW_FILEINFO_NAME_INFORMATION
},
108 { .name
="POSITION_INFORMATION",
109 .level
= RAW_FILEINFO_POSITION_INFORMATION
},
110 { .name
="MODE_INFORMATION",
111 .level
= RAW_FILEINFO_MODE_INFORMATION
},
112 { .name
="ALIGNMENT_INFORMATION",
113 .level
= RAW_FILEINFO_ALIGNMENT_INFORMATION
},
114 { .name
="ALL_INFORMATION",
115 .level
= RAW_FILEINFO_ALL_INFORMATION
},
116 { .name
="ALT_NAME_INFORMATION",
117 .level
= RAW_FILEINFO_ALT_NAME_INFORMATION
,
118 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
120 { .name
="STREAM_INFORMATION",
121 .level
= RAW_FILEINFO_STREAM_INFORMATION
,
122 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
124 { .name
= "COMPRESSION_INFORMATION",
125 .level
= RAW_FILEINFO_COMPRESSION_INFORMATION
,
126 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
128 { .name
="NETWORK_OPEN_INFORMATION",
129 .level
= RAW_FILEINFO_NETWORK_OPEN_INFORMATION
,
130 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
132 { .name
= "ATTRIBUTE_TAG_INFORMATION",
133 .level
= RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
,
134 .expected_ipc_fnum_status
= NT_STATUS_INVALID_PARAMETER
140 compare a dos time (2 second resolution) to a nt time
142 static int dos_nt_time_cmp(time_t t
, NTTIME nt
)
144 time_t t2
= nt_time_to_unix(nt
);
145 if (abs(t2
- t
) <= 2) return 0;
151 find a level in the levels[] table
153 static union smb_fileinfo
*fnum_find(const char *name
)
156 for (i
=0; levels
[i
].name
; i
++) {
157 if (NT_STATUS_IS_OK(levels
[i
].fnum_status
) &&
158 strcmp(name
, levels
[i
].name
) == 0 &&
159 !levels
[i
].only_paths
) {
160 return &levels
[i
].fnum_finfo
;
167 find a level in the levels[] table
169 static union smb_fileinfo
*fname_find(bool is_ipc
, const char *name
)
175 for (i
=0; levels
[i
].name
; i
++) {
176 if (NT_STATUS_IS_OK(levels
[i
].fname_status
) &&
177 strcmp(name
, levels
[i
].name
) == 0 &&
178 !levels
[i
].only_handles
) {
179 return &levels
[i
].fname_finfo
;
185 /* local macros to make the code below more readable */
186 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
187 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
188 #n1, #v1, (uint_t)s1->n1.out.v1, \
189 #n2, #v2, (uint_t)s2->n2.out.v2, \
190 __FILE__, __LINE__); \
194 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
195 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
196 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
197 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
198 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
199 __FILE__, __LINE__); \
203 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
204 printf("%s/%s != %s/%s at %s(%d)\n", \
207 __FILE__, __LINE__); \
211 /* used to find hints on unknown values - and to make sure
214 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
215 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
217 (uint_t)s1->n1.out.v1, \
218 (uint_t)s1->n1.out.v1, \
219 __FILE__, __LINE__); \
224 /* basic testing of all RAW_FILEINFO_* calls
225 for each call we test that it succeeds, and where possible test
226 for consistency between the calls.
228 static bool torture_raw_qfileinfo_internals(struct torture_context
*torture
,
230 struct smbcli_tree
*tree
,
231 int fnum
, const char *fname
,
237 union smb_fileinfo
*s1
, *s2
;
239 uint64_t correct_size
;
240 uint32_t correct_attrib
;
241 const char *correct_name
;
242 bool skip_streams
= false;
244 /* scan all the fileinfo and pathinfo levels */
245 for (i
=0; levels
[i
].name
; i
++) {
246 if (!levels
[i
].only_paths
) {
247 levels
[i
].fnum_finfo
.generic
.level
= levels
[i
].level
;
248 levels
[i
].fnum_finfo
.generic
.in
.file
.fnum
= fnum
;
249 levels
[i
].fnum_status
= smb_raw_fileinfo(tree
, mem_ctx
,
250 &levels
[i
].fnum_finfo
);
253 if (!levels
[i
].only_handles
) {
254 levels
[i
].fname_finfo
.generic
.level
= levels
[i
].level
;
255 levels
[i
].fname_finfo
.generic
.in
.file
.path
= talloc_strdup(mem_ctx
, fname
);
256 levels
[i
].fname_status
= smb_raw_pathinfo(tree
, mem_ctx
,
257 &levels
[i
].fname_finfo
);
261 /* check for completely broken levels */
262 for (count
=i
=0; levels
[i
].name
; i
++) {
263 uint32_t cap
= tree
->session
->transport
->negotiate
.capabilities
;
264 /* see if this server claims to support this level */
265 if ((cap
& levels
[i
].capability_mask
) != levels
[i
].capability_mask
) {
270 if (levels
[i
].expected_ipc_access_denied
&& NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED
, levels
[i
].fname_status
)) {
271 } else if (!levels
[i
].only_handles
&& !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST
, levels
[i
].fname_status
)) {
272 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n",
273 levels
[i
].name
, nt_errstr(levels
[i
].fname_status
));
276 if (!levels
[i
].only_paths
&& !NT_STATUS_EQUAL(levels
[i
].expected_ipc_fnum_status
, levels
[i
].fnum_status
)) {
277 printf("ERROR: fnum level %s failed, expected %s - %s\n",
278 levels
[i
].name
, nt_errstr(levels
[i
].expected_ipc_fnum_status
),
279 nt_errstr(levels
[i
].fnum_status
));
283 if (!levels
[i
].only_paths
&& !NT_STATUS_IS_OK(levels
[i
].fnum_status
)) {
284 printf("ERROR: fnum level %s failed - %s\n",
285 levels
[i
].name
, nt_errstr(levels
[i
].fnum_status
));
288 if (!levels
[i
].only_handles
&& !NT_STATUS_IS_OK(levels
[i
].fname_status
)) {
289 printf("ERROR: fname level %s failed - %s\n",
290 levels
[i
].name
, nt_errstr(levels
[i
].fname_status
));
299 printf("%d levels failed\n", count
);
301 torture_fail(torture
, "too many level failures - giving up");
305 /* see if we can do streams */
306 s1
= fnum_find("STREAM_INFO");
307 if (!s1
|| s1
->stream_info
.out
.num_streams
== 0) {
309 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
310 s1
? s1
->stream_info
.out
.num_streams
: -1);
316 /* this code is incredibly repititive but doesn't lend itself to loops, so
317 we use lots of macros to make it less painful */
319 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
320 this code to fail, but we need to check it for completeness */
324 #define ALIAS_CHECK(sname1, sname2) \
326 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
327 if (s1 && s2) { INFO_CHECK } \
328 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
329 if (s1 && s2) { INFO_CHECK } \
330 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
331 if (s1 && s2) { INFO_CHECK } \
335 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
336 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
337 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
338 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
339 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
341 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
345 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
346 VAL_EQUAL(standard_info, size, standard_info, size); \
347 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
348 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
349 VAL_EQUAL(standard_info, directory, standard_info, directory);
351 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
355 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
357 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
361 STR_EQUAL(name_info, fname, name_info, fname);
363 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
367 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
368 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
369 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
370 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
371 VAL_EQUAL(all_info, attrib, all_info, attrib); \
372 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
373 VAL_EQUAL(all_info, size, all_info, size); \
374 VAL_EQUAL(all_info, nlink, all_info, nlink); \
375 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
376 VAL_EQUAL(all_info, directory, all_info, directory); \
377 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
378 STR_EQUAL(all_info, fname, all_info, fname);
380 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
384 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
385 VAL_EQUAL(compression_info, format, compression_info, format); \
386 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
387 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
388 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
390 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
395 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
397 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
400 #define TIME_CHECK_NT(sname, stype, tfield) do { \
401 s1 = fnum_find(sname); \
402 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
403 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
404 nt_time_string(mem_ctx, s1->stype.out.tfield), \
405 nt_time_string(mem_ctx, correct_time)); \
408 s1 = fname_find(is_ipc, sname); \
409 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
410 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
411 nt_time_string(mem_ctx, s1->stype.out.tfield), \
412 nt_time_string(mem_ctx, correct_time)); \
416 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
417 s1 = fnum_find(sname); \
418 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
419 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
420 timestring(mem_ctx, s1->stype.out.tfield), \
421 nt_time_string(mem_ctx, correct_time)); \
424 s1 = fname_find(is_ipc, sname); \
425 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
426 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
427 timestring(mem_ctx, s1->stype.out.tfield), \
428 nt_time_string(mem_ctx, correct_time)); \
433 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
434 s1 = fnum_find(sname); \
435 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
436 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
437 timestring(mem_ctx, s1->stype.out.tfield), \
438 nt_time_string(mem_ctx, correct_time)); \
441 s1 = fname_find(is_ipc, sname); \
442 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
443 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
444 timestring(mem_ctx, s1->stype.out.tfield), \
445 nt_time_string(mem_ctx, correct_time)); \
450 /* now check that all the times that are supposed to be equal are correct */
451 s1
= fnum_find("BASIC_INFO");
452 correct_time
= s1
->basic_info
.out
.create_time
;
453 torture_comment(torture
, "create_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
455 TIME_CHECK_NT ("BASIC_INFO", basic_info
, create_time
);
456 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, create_time
);
457 TIME_CHECK_DOS("GETATTRE", getattre
, create_time
);
458 TIME_CHECK_DOS("STANDARD", standard
, create_time
);
459 TIME_CHECK_DOS("EA_SIZE", ea_size
, create_time
);
460 TIME_CHECK_NT ("ALL_INFO", all_info
, create_time
);
461 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, create_time
);
463 s1
= fnum_find("BASIC_INFO");
464 correct_time
= s1
->basic_info
.out
.access_time
;
465 torture_comment(torture
, "access_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
467 TIME_CHECK_NT ("BASIC_INFO", basic_info
, access_time
);
468 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, access_time
);
469 TIME_CHECK_DOS("GETATTRE", getattre
, access_time
);
470 TIME_CHECK_DOS("STANDARD", standard
, access_time
);
471 TIME_CHECK_DOS("EA_SIZE", ea_size
, access_time
);
472 TIME_CHECK_NT ("ALL_INFO", all_info
, access_time
);
473 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, access_time
);
475 s1
= fnum_find("BASIC_INFO");
476 correct_time
= s1
->basic_info
.out
.write_time
;
477 torture_comment(torture
, "write_time : %s\n", nt_time_string(mem_ctx
, correct_time
));
479 TIME_CHECK_NT ("BASIC_INFO", basic_info
, write_time
);
480 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, write_time
);
481 TIME_CHECK_DOS("GETATTR", getattr
, write_time
);
482 TIME_CHECK_DOS("GETATTRE", getattre
, write_time
);
483 TIME_CHECK_DOS("STANDARD", standard
, write_time
);
484 TIME_CHECK_DOS("EA_SIZE", ea_size
, write_time
);
485 TIME_CHECK_NT ("ALL_INFO", all_info
, write_time
);
486 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, write_time
);
488 s1
= fnum_find("BASIC_INFO");
489 correct_time
= s1
->basic_info
.out
.change_time
;
490 torture_comment(torture
, "change_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
492 TIME_CHECK_NT ("BASIC_INFO", basic_info
, change_time
);
493 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, change_time
);
494 TIME_CHECK_NT ("ALL_INFO", all_info
, change_time
);
495 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, change_time
);
498 #define SIZE_CHECK(sname, stype, tfield) do { \
499 s1 = fnum_find(sname); \
500 if (s1 && s1->stype.out.tfield != correct_size) { \
501 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
502 (uint_t)s1->stype.out.tfield, \
503 (uint_t)correct_size); \
506 s1 = fname_find(is_ipc, sname); \
507 if (s1 && s1->stype.out.tfield != correct_size) { \
508 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
509 (uint_t)s1->stype.out.tfield, \
510 (uint_t)correct_size); \
514 s1
= fnum_find("STANDARD_INFO");
515 correct_size
= s1
->standard_info
.out
.size
;
516 torture_comment(torture
, "size: %u\n", (uint_t
)correct_size
);
518 SIZE_CHECK("GETATTR", getattr
, size
);
519 SIZE_CHECK("GETATTRE", getattre
, size
);
520 SIZE_CHECK("STANDARD", standard
, size
);
521 SIZE_CHECK("EA_SIZE", ea_size
, size
);
522 SIZE_CHECK("STANDARD_INFO", standard_info
, size
);
523 SIZE_CHECK("STANDARD_INFORMATION", standard_info
, size
);
524 SIZE_CHECK("ALL_INFO", all_info
, size
);
525 SIZE_CHECK("ALL_INFORMATION", all_info
, size
);
526 SIZE_CHECK("COMPRESSION_INFO", compression_info
, compressed_size
);
527 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info
, compressed_size
);
528 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, size
);
530 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].size
);
531 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].size
);
535 s1
= fnum_find("STANDARD_INFO");
536 correct_size
= s1
->standard_info
.out
.alloc_size
;
537 torture_comment(torture
, "alloc_size: %u\n", (uint_t
)correct_size
);
539 SIZE_CHECK("GETATTRE", getattre
, alloc_size
);
540 SIZE_CHECK("STANDARD", standard
, alloc_size
);
541 SIZE_CHECK("EA_SIZE", ea_size
, alloc_size
);
542 SIZE_CHECK("STANDARD_INFO", standard_info
, alloc_size
);
543 SIZE_CHECK("STANDARD_INFORMATION", standard_info
, alloc_size
);
544 SIZE_CHECK("ALL_INFO", all_info
, alloc_size
);
545 SIZE_CHECK("ALL_INFORMATION", all_info
, alloc_size
);
546 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, alloc_size
);
548 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].alloc_size
);
549 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].alloc_size
);
552 #define ATTRIB_CHECK(sname, stype, tfield) do { \
553 s1 = fnum_find(sname); \
554 if (s1 && s1->stype.out.tfield != correct_attrib) { \
555 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
556 (uint_t)s1->stype.out.tfield, \
557 (uint_t)correct_attrib); \
560 s1 = fname_find(is_ipc, sname); \
561 if (s1 && s1->stype.out.tfield != correct_attrib) { \
562 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
563 (uint_t)s1->stype.out.tfield, \
564 (uint_t)correct_attrib); \
568 s1
= fnum_find("BASIC_INFO");
569 correct_attrib
= s1
->basic_info
.out
.attrib
;
570 torture_comment(torture
, "attrib: 0x%x\n", (uint_t
)correct_attrib
);
572 ATTRIB_CHECK("GETATTR", getattr
, attrib
);
574 ATTRIB_CHECK("GETATTRE", getattre
, attrib
);
575 ATTRIB_CHECK("STANDARD", standard
, attrib
);
576 ATTRIB_CHECK("EA_SIZE", ea_size
, attrib
);
578 ATTRIB_CHECK("BASIC_INFO", basic_info
, attrib
);
579 ATTRIB_CHECK("BASIC_INFORMATION", basic_info
, attrib
);
580 ATTRIB_CHECK("ALL_INFO", all_info
, attrib
);
581 ATTRIB_CHECK("ALL_INFORMATION", all_info
, attrib
);
582 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, attrib
);
583 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, attrib
);
585 correct_name
= fname
;
586 torture_comment(torture
, "name: %s\n", correct_name
);
588 #define NAME_CHECK(sname, stype, tfield, flags) do { \
589 s1 = fnum_find(sname); \
590 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
591 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
592 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
593 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
596 s1 = fname_find(is_ipc, sname); \
597 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
598 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
599 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
600 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
604 NAME_CHECK("NAME_INFO", name_info
, fname
, STR_UNICODE
);
605 NAME_CHECK("NAME_INFORMATION", name_info
, fname
, STR_UNICODE
);
607 /* the ALL_INFO file name is the full path on the filesystem */
608 s1
= fnum_find("ALL_INFO");
609 if (s1
&& !s1
->all_info
.out
.fname
.s
) {
610 torture_fail(torture
, "ALL_INFO didn't give a filename");
612 if (s1
&& s1
->all_info
.out
.fname
.s
) {
613 char *p
= strrchr(s1
->all_info
.out
.fname
.s
, '\\');
615 printf("Not a full path in all_info/fname? - '%s'\n",
616 s1
->all_info
.out
.fname
.s
);
619 if (strcmp_safe(correct_name
, p
) != 0) {
620 printf("incorrect basename in all_info/fname - '%s'\n",
621 s1
->all_info
.out
.fname
.s
);
625 if (wire_bad_flags(&s1
->all_info
.out
.fname
, STR_UNICODE
, tree
->session
->transport
)) {
626 printf("Should not null terminate all_info/fname\n");
631 s1
= fnum_find("ALT_NAME_INFO");
633 correct_name
= s1
->alt_name_info
.out
.fname
.s
;
634 torture_comment(torture
, "alt_name: %s\n", correct_name
);
636 NAME_CHECK("ALT_NAME_INFO", alt_name_info
, fname
, STR_UNICODE
);
637 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info
, fname
, STR_UNICODE
);
639 /* and make sure we can open by alternate name */
640 smbcli_close(tree
, fnum
);
641 fnum
= smbcli_nt_create_full(tree
, correct_name
, 0,
643 FILE_ATTRIBUTE_NORMAL
,
644 NTCREATEX_SHARE_ACCESS_DELETE
|
645 NTCREATEX_SHARE_ACCESS_READ
|
646 NTCREATEX_SHARE_ACCESS_WRITE
,
647 NTCREATEX_DISP_OVERWRITE_IF
,
650 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree
));
655 correct_name
= "::$DATA";
656 torture_comment(torture
, "stream_name: %s\n", correct_name
);
658 NAME_CHECK("STREAM_INFO", stream_info
, streams
[0].stream_name
, STR_UNICODE
);
659 NAME_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].stream_name
, STR_UNICODE
);
663 /* make sure the EAs look right */
664 s1
= fnum_find("ALL_EAS");
665 s2
= fnum_find("ALL_INFO");
667 for (i
=0;i
<s1
->all_eas
.out
.num_eas
;i
++) {
668 printf(" flags=%d %s=%*.*s\n",
669 s1
->all_eas
.out
.eas
[i
].flags
,
670 s1
->all_eas
.out
.eas
[i
].name
.s
,
671 (int)s1
->all_eas
.out
.eas
[i
].value
.length
,
672 (int)s1
->all_eas
.out
.eas
[i
].value
.length
,
673 s1
->all_eas
.out
.eas
[i
].value
.data
);
677 if (s1
->all_eas
.out
.num_eas
== 0) {
678 if (s2
->all_info
.out
.ea_size
!= 0) {
679 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
680 s2
->all_info
.out
.ea_size
);
683 if (s2
->all_info
.out
.ea_size
!=
684 ea_list_size(s1
->all_eas
.out
.num_eas
, s1
->all_eas
.out
.eas
)) {
685 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
686 (int)ea_list_size(s1
->all_eas
.out
.num_eas
, s1
->all_eas
.out
.eas
),
687 (int)s2
->all_info
.out
.ea_size
);
691 s2
= fname_find(is_ipc
, "ALL_EAS");
693 VAL_EQUAL(all_eas
, num_eas
, all_eas
, num_eas
);
694 for (i
=0;i
<s1
->all_eas
.out
.num_eas
;i
++) {
695 VAL_EQUAL(all_eas
, eas
[i
].flags
, all_eas
, eas
[i
].flags
);
696 STR_EQUAL(all_eas
, eas
[i
].name
, all_eas
, eas
[i
].name
);
697 VAL_EQUAL(all_eas
, eas
[i
].value
.length
, all_eas
, eas
[i
].value
.length
);
701 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
702 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
703 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
704 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
705 #stype1, #tfield1, #stype2, #tfield2, \
706 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
709 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
710 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
711 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
712 #stype1, #tfield1, #stype2, #tfield2, \
713 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
716 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
717 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
718 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
719 #stype1, #tfield1, #stype2, #tfield2, \
720 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
723 s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
724 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
725 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
726 #stype1, #tfield1, #stype2, #tfield2, \
727 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
731 VAL_CHECK("STANDARD_INFO", standard_info
, delete_pending
,
732 "ALL_INFO", all_info
, delete_pending
);
733 VAL_CHECK("STANDARD_INFO", standard_info
, directory
,
734 "ALL_INFO", all_info
, directory
);
735 VAL_CHECK("STANDARD_INFO", standard_info
, nlink
,
736 "ALL_INFO", all_info
, nlink
);
737 s1
= fnum_find("BASIC_INFO");
739 if (s1
->basic_info
.out
.attrib
!= FILE_ATTRIBUTE_NORMAL
) {
740 printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__
, s1
->basic_info
.out
.attrib
, FILE_ATTRIBUTE_NORMAL
);
744 s1
= fnum_find("STANDARD_INFO");
746 if (s1
->standard_info
.out
.nlink
!= 1) {
747 printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__
, s1
->standard_info
.out
.nlink
);
750 if (s1
->standard_info
.out
.delete_pending
!= 1) {
751 printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__
, s1
->standard_info
.out
.delete_pending
);
755 VAL_CHECK("EA_INFO", ea_info
, ea_size
,
756 "ALL_INFO", all_info
, ea_size
);
758 VAL_CHECK("EA_SIZE", ea_size
, ea_size
,
759 "ALL_INFO", all_info
, ea_size
);
762 #define NAME_PATH_CHECK(sname, stype, field) do { \
763 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
765 VAL_EQUAL(stype, field, stype, field); \
770 s1
= fnum_find("INTERNAL_INFORMATION");
772 torture_comment(torture
, "file_id=%.0f\n", (double)s1
->internal_information
.out
.file_id
);
775 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information
, file_id
);
776 NAME_PATH_CHECK("POSITION_INFORMATION", position_information
, position
);
778 printf("fnum pos = %.0f, fname pos = %.0f\n",
779 (double)s2
->position_information
.out
.position
,
780 (double)s1
->position_information
.out
.position
);
782 NAME_PATH_CHECK("MODE_INFORMATION", mode_information
, mode
);
783 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information
, alignment_requirement
);
784 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, attrib
);
785 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, reparse_tag
);
788 /* these are expected to differ */
789 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information
, access_flags
);
793 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
794 s1 = fnum_find(sname); \
795 if (s1 && s1->stype.out.tfield != 0) { \
796 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
798 (uint_t)s1->stype.out.tfield); \
800 s1 = fname_find(is_ipc, sname); \
801 if (s1 && s1->stype.out.tfield != 0) { \
802 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
804 (uint_t)s1->stype.out.tfield); \
807 /* now get a bit fancier .... */
809 /* when we set the delete disposition then the link count should drop
810 to 0 and delete_pending should be 1 */
815 /* basic testing of all RAW_FILEINFO_* calls
816 for each call we test that it succeeds, and where possible test
817 for consistency between the calls.
819 bool torture_raw_qfileinfo(struct torture_context
*torture
,
820 struct smbcli_state
*cli
)
824 const char *fname
= "\\torture_qfileinfo.txt";
826 fnum
= create_complex_file(cli
, torture
, fname
);
828 printf("ERROR: open of %s failed (%s)\n", fname
, smbcli_errstr(cli
->tree
));
832 ret
= torture_raw_qfileinfo_internals(torture
, torture
, cli
->tree
, fnum
, fname
, false /* is_ipc */);
834 smbcli_close(cli
->tree
, fnum
);
835 smbcli_unlink(cli
->tree
, fname
);
840 bool torture_raw_qfileinfo_pipe(struct torture_context
*torture
,
841 struct smbcli_state
*cli
)
845 const char *fname
= "\\lsass";
846 struct dcerpc_pipe
*p
;
847 struct smbcli_tree
*ipc_tree
;
850 if (!(p
= dcerpc_pipe_init(torture
, cli
->tree
->session
->transport
->socket
->event
.ctx
,
851 lp_iconv_convenience(torture
->lp_ctx
)))) {
855 status
= dcerpc_pipe_open_smb(p
, cli
->tree
, fname
);
856 torture_assert_ntstatus_ok(torture
, status
, "dcerpc_pipe_open_smb failed");
858 ipc_tree
= dcerpc_smb_tree(p
->conn
);
859 fnum
= dcerpc_smb_fnum(p
->conn
);
861 ret
= torture_raw_qfileinfo_internals(torture
, torture
, ipc_tree
, fnum
, fname
, true /* is_ipc */);