2 Unix SMB/CIFS implementation.
3 RAW_FILEINFO_* individual test suite
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "torture/rpc/rpc.h"
31 enum smb_fileinfo_level level
;
33 uint_t only_handles
:1;
34 uint32_t capability_mask
;
35 NTSTATUS fnum_status
, fname_status
;
36 union smb_fileinfo fnum_finfo
, fname_finfo
;
38 { "GETATTR", RAW_FILEINFO_GETATTR
, 1, 0, },
39 { "GETATTRE", RAW_FILEINFO_GETATTRE
, 0, 1, },
40 { "STANDARD", RAW_FILEINFO_STANDARD
, },
41 { "EA_SIZE", RAW_FILEINFO_EA_SIZE
, },
42 { "ALL_EAS", RAW_FILEINFO_ALL_EAS
, },
43 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID
, 1, 0, },
44 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO
, },
45 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO
, },
46 { "EA_INFO", RAW_FILEINFO_EA_INFO
, },
47 { "NAME_INFO", RAW_FILEINFO_NAME_INFO
, },
48 { "ALL_INFO", RAW_FILEINFO_ALL_INFO
, },
49 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO
, },
50 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO
, },
51 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO
, },
52 { "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC
, 0, 0, CAP_UNIX
},
53 { "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK
, 0, 0, CAP_UNIX
},
54 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION
, },
55 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION
, },
56 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION
, },
57 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION
, },
58 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION
, },
59 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION
, },
60 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION
, },
61 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION
, },
62 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION
, },
63 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION
, },
64 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION
, },
65 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION
, },
66 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION
, },
67 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION
, },
68 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
, },
75 compare a dos time (2 second resolution) to a nt time
77 static int dos_nt_time_cmp(time_t t
, NTTIME nt
)
79 time_t t2
= nt_time_to_unix(nt
);
80 if (abs(t2
- t
) <= 2) return 0;
86 find a level in the levels[] table
88 static union smb_fileinfo
*fnum_find(const char *name
)
91 for (i
=0; levels
[i
].name
; i
++) {
92 if (NT_STATUS_IS_OK(levels
[i
].fnum_status
) &&
93 strcmp(name
, levels
[i
].name
) == 0 &&
94 !levels
[i
].only_paths
) {
95 return &levels
[i
].fnum_finfo
;
102 find a level in the levels[] table
104 static union smb_fileinfo
*fname_find(const char *name
)
110 for (i
=0; levels
[i
].name
; i
++) {
111 if (NT_STATUS_IS_OK(levels
[i
].fname_status
) &&
112 strcmp(name
, levels
[i
].name
) == 0 &&
113 !levels
[i
].only_handles
) {
114 return &levels
[i
].fname_finfo
;
120 /* local macros to make the code below more readable */
121 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
122 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
123 #n1, #v1, (uint_t)s1->n1.out.v1, \
124 #n2, #v2, (uint_t)s2->n2.out.v2, \
125 __FILE__, __LINE__); \
129 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
130 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
131 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
132 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
133 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
134 __FILE__, __LINE__); \
138 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
139 printf("%s/%s != %s/%s at %s(%d)\n", \
142 __FILE__, __LINE__); \
146 /* used to find hints on unknown values - and to make sure
149 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
150 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
152 (uint_t)s1->n1.out.v1, \
153 (uint_t)s1->n1.out.v1, \
154 __FILE__, __LINE__); \
159 /* basic testing of all RAW_FILEINFO_* calls
160 for each call we test that it succeeds, and where possible test
161 for consistency between the calls.
163 static BOOL
torture_raw_qfileinfo_internals(struct torture_context
*torture
, TALLOC_CTX
*mem_ctx
,
164 struct smbcli_tree
*tree
, int fnum
, const char *fname
)
169 union smb_fileinfo
*s1
, *s2
;
171 uint64_t correct_size
;
172 uint32_t correct_attrib
;
173 const char *correct_name
;
174 BOOL skip_streams
= False
;
176 /* scan all the fileinfo and pathinfo levels */
177 for (i
=0; levels
[i
].name
; i
++) {
178 if (!levels
[i
].only_paths
) {
179 levels
[i
].fnum_finfo
.generic
.level
= levels
[i
].level
;
180 levels
[i
].fnum_finfo
.generic
.in
.file
.fnum
= fnum
;
181 levels
[i
].fnum_status
= smb_raw_fileinfo(tree
, mem_ctx
,
182 &levels
[i
].fnum_finfo
);
185 if (!levels
[i
].only_handles
) {
186 levels
[i
].fname_finfo
.generic
.level
= levels
[i
].level
;
187 levels
[i
].fname_finfo
.generic
.in
.file
.path
= talloc_strdup(mem_ctx
, fname
);
188 levels
[i
].fname_status
= smb_raw_pathinfo(tree
, mem_ctx
,
189 &levels
[i
].fname_finfo
);
193 /* check for completely broken levels */
194 for (count
=i
=0; levels
[i
].name
; i
++) {
195 uint32_t cap
= tree
->session
->transport
->negotiate
.capabilities
;
196 /* see if this server claims to support this level */
197 if ((cap
& levels
[i
].capability_mask
) != levels
[i
].capability_mask
) {
201 if (!levels
[i
].only_paths
&& !NT_STATUS_IS_OK(levels
[i
].fnum_status
)) {
202 printf("ERROR: level %s failed - %s\n",
203 levels
[i
].name
, nt_errstr(levels
[i
].fnum_status
));
206 if (!(is_ipc
|| levels
[i
].only_handles
) && !NT_STATUS_IS_OK(levels
[i
].fname_status
)) {
207 printf("ERROR: level %s failed - %s\n",
208 levels
[i
].name
, nt_errstr(levels
[i
].fname_status
));
215 printf("%d levels failed\n", count
);
217 printf("too many level failures - giving up\n");
222 /* see if we can do streams */
223 s1
= fnum_find("STREAM_INFO");
224 if (!s1
|| s1
->stream_info
.out
.num_streams
== 0) {
226 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
227 s1
? s1
->stream_info
.out
.num_streams
: -1);
233 /* this code is incredibly repititive but doesn't lend itself to loops, so
234 we use lots of macros to make it less painful */
236 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
237 this code to fail, but we need to check it for completeness */
241 #define ALIAS_CHECK(sname1, sname2) \
243 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
244 if (s1 && s2) { INFO_CHECK } \
245 s1 = fname_find(sname1); s2 = fname_find(sname2); \
246 if (s1 && s2) { INFO_CHECK } \
247 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
248 if (s1 && s2) { INFO_CHECK } \
252 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
253 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
254 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
255 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
256 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
258 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
262 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
263 VAL_EQUAL(standard_info, size, standard_info, size); \
264 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
265 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
266 VAL_EQUAL(standard_info, directory, standard_info, directory);
268 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
272 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
274 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
278 STR_EQUAL(name_info, fname, name_info, fname);
280 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
284 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
285 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
286 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
287 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
288 VAL_EQUAL(all_info, attrib, all_info, attrib); \
289 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
290 VAL_EQUAL(all_info, size, all_info, size); \
291 VAL_EQUAL(all_info, nlink, all_info, nlink); \
292 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
293 VAL_EQUAL(all_info, directory, all_info, directory); \
294 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
295 STR_EQUAL(all_info, fname, all_info, fname);
297 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
301 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
302 VAL_EQUAL(compression_info, format, compression_info, format); \
303 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
304 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
305 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
307 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
312 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
314 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
317 #define TIME_CHECK_NT(sname, stype, tfield) do { \
318 s1 = fnum_find(sname); \
319 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
320 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
321 nt_time_string(mem_ctx, s1->stype.out.tfield), \
322 nt_time_string(mem_ctx, correct_time)); \
325 s1 = fname_find(sname); \
326 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
327 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
328 nt_time_string(mem_ctx, s1->stype.out.tfield), \
329 nt_time_string(mem_ctx, correct_time)); \
333 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
334 s1 = fnum_find(sname); \
335 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
336 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
337 timestring(mem_ctx, s1->stype.out.tfield), \
338 nt_time_string(mem_ctx, correct_time)); \
341 s1 = fname_find(sname); \
342 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
343 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
344 timestring(mem_ctx, s1->stype.out.tfield), \
345 nt_time_string(mem_ctx, correct_time)); \
350 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
351 s1 = fnum_find(sname); \
352 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
353 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
354 timestring(mem_ctx, s1->stype.out.tfield), \
355 nt_time_string(mem_ctx, correct_time)); \
358 s1 = fname_find(sname); \
359 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
360 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
361 timestring(mem_ctx, s1->stype.out.tfield), \
362 nt_time_string(mem_ctx, correct_time)); \
367 /* now check that all the times that are supposed to be equal are correct */
368 s1
= fnum_find("BASIC_INFO");
369 correct_time
= s1
->basic_info
.out
.create_time
;
370 printf("create_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
372 TIME_CHECK_NT ("BASIC_INFO", basic_info
, create_time
);
373 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, create_time
);
374 TIME_CHECK_DOS("GETATTRE", getattre
, create_time
);
375 TIME_CHECK_DOS("STANDARD", standard
, create_time
);
376 TIME_CHECK_DOS("EA_SIZE", ea_size
, create_time
);
377 TIME_CHECK_NT ("ALL_INFO", all_info
, create_time
);
378 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, create_time
);
380 s1
= fnum_find("BASIC_INFO");
381 correct_time
= s1
->basic_info
.out
.access_time
;
382 printf("access_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
384 TIME_CHECK_NT ("BASIC_INFO", basic_info
, access_time
);
385 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, access_time
);
386 TIME_CHECK_DOS("GETATTRE", getattre
, access_time
);
387 TIME_CHECK_DOS("STANDARD", standard
, access_time
);
388 TIME_CHECK_DOS("EA_SIZE", ea_size
, access_time
);
389 TIME_CHECK_NT ("ALL_INFO", all_info
, access_time
);
390 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, access_time
);
392 s1
= fnum_find("BASIC_INFO");
393 correct_time
= s1
->basic_info
.out
.write_time
;
394 printf("write_time : %s\n", nt_time_string(mem_ctx
, correct_time
));
396 TIME_CHECK_NT ("BASIC_INFO", basic_info
, write_time
);
397 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, write_time
);
398 TIME_CHECK_DOS("GETATTR", getattr
, write_time
);
399 TIME_CHECK_DOS("GETATTRE", getattre
, write_time
);
400 TIME_CHECK_DOS("STANDARD", standard
, write_time
);
401 TIME_CHECK_DOS("EA_SIZE", ea_size
, write_time
);
402 TIME_CHECK_NT ("ALL_INFO", all_info
, write_time
);
403 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, write_time
);
405 s1
= fnum_find("BASIC_INFO");
406 correct_time
= s1
->basic_info
.out
.change_time
;
407 printf("change_time: %s\n", nt_time_string(mem_ctx
, correct_time
));
409 TIME_CHECK_NT ("BASIC_INFO", basic_info
, change_time
);
410 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info
, change_time
);
411 TIME_CHECK_NT ("ALL_INFO", all_info
, change_time
);
412 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information
, change_time
);
415 #define SIZE_CHECK(sname, stype, tfield) do { \
416 s1 = fnum_find(sname); \
417 if (s1 && s1->stype.out.tfield != correct_size) { \
418 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
419 (uint_t)s1->stype.out.tfield, \
420 (uint_t)correct_size); \
423 s1 = fname_find(sname); \
424 if (s1 && s1->stype.out.tfield != correct_size) { \
425 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
426 (uint_t)s1->stype.out.tfield, \
427 (uint_t)correct_size); \
431 s1
= fnum_find("STANDARD_INFO");
432 correct_size
= s1
->standard_info
.out
.size
;
433 printf("size: %u\n", (uint_t
)correct_size
);
435 SIZE_CHECK("GETATTR", getattr
, size
);
436 SIZE_CHECK("GETATTRE", getattre
, size
);
437 SIZE_CHECK("STANDARD", standard
, size
);
438 SIZE_CHECK("EA_SIZE", ea_size
, size
);
439 SIZE_CHECK("STANDARD_INFO", standard_info
, size
);
440 SIZE_CHECK("STANDARD_INFORMATION", standard_info
, size
);
441 SIZE_CHECK("ALL_INFO", all_info
, size
);
442 SIZE_CHECK("ALL_INFORMATION", all_info
, size
);
443 SIZE_CHECK("COMPRESSION_INFO", compression_info
, compressed_size
);
444 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info
, compressed_size
);
445 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, size
);
447 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].size
);
448 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].size
);
452 s1
= fnum_find("STANDARD_INFO");
453 correct_size
= s1
->standard_info
.out
.alloc_size
;
454 printf("alloc_size: %u\n", (uint_t
)correct_size
);
456 SIZE_CHECK("GETATTRE", getattre
, alloc_size
);
457 SIZE_CHECK("STANDARD", standard
, alloc_size
);
458 SIZE_CHECK("EA_SIZE", ea_size
, alloc_size
);
459 SIZE_CHECK("STANDARD_INFO", standard_info
, alloc_size
);
460 SIZE_CHECK("STANDARD_INFORMATION", standard_info
, alloc_size
);
461 SIZE_CHECK("ALL_INFO", all_info
, alloc_size
);
462 SIZE_CHECK("ALL_INFORMATION", all_info
, alloc_size
);
463 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, alloc_size
);
465 SIZE_CHECK("STREAM_INFO", stream_info
, streams
[0].alloc_size
);
466 SIZE_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].alloc_size
);
469 #define ATTRIB_CHECK(sname, stype, tfield) do { \
470 s1 = fnum_find(sname); \
471 if (s1 && s1->stype.out.tfield != correct_attrib) { \
472 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
473 (uint_t)s1->stype.out.tfield, \
474 (uint_t)correct_attrib); \
477 s1 = fname_find(sname); \
478 if (s1 && s1->stype.out.tfield != correct_attrib) { \
479 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
480 (uint_t)s1->stype.out.tfield, \
481 (uint_t)correct_attrib); \
485 s1
= fnum_find("BASIC_INFO");
486 correct_attrib
= s1
->basic_info
.out
.attrib
;
487 printf("attrib: 0x%x\n", (uint_t
)correct_attrib
);
489 ATTRIB_CHECK("GETATTR", getattr
, attrib
);
490 ATTRIB_CHECK("GETATTRE", getattre
, attrib
);
491 ATTRIB_CHECK("STANDARD", standard
, attrib
);
492 ATTRIB_CHECK("BASIC_INFO", basic_info
, attrib
);
493 ATTRIB_CHECK("BASIC_INFORMATION", basic_info
, attrib
);
494 ATTRIB_CHECK("EA_SIZE", ea_size
, attrib
);
495 ATTRIB_CHECK("ALL_INFO", all_info
, attrib
);
496 ATTRIB_CHECK("ALL_INFORMATION", all_info
, attrib
);
497 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information
, attrib
);
498 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, attrib
);
500 correct_name
= fname
;
501 printf("name: %s\n", correct_name
);
503 #define NAME_CHECK(sname, stype, tfield, flags) do { \
504 s1 = fnum_find(sname); \
505 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
506 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
507 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
508 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
511 s1 = fname_find(sname); \
512 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
513 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
514 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
515 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
519 NAME_CHECK("NAME_INFO", name_info
, fname
, STR_UNICODE
);
520 NAME_CHECK("NAME_INFORMATION", name_info
, fname
, STR_UNICODE
);
522 /* the ALL_INFO file name is the full path on the filesystem */
523 s1
= fnum_find("ALL_INFO");
524 if (s1
&& !s1
->all_info
.out
.fname
.s
) {
525 printf("ALL_INFO didn't give a filename\n");
528 if (s1
&& s1
->all_info
.out
.fname
.s
) {
529 char *p
= strrchr(s1
->all_info
.out
.fname
.s
, '\\');
531 printf("Not a full path in all_info/fname? - '%s'\n",
532 s1
->all_info
.out
.fname
.s
);
535 if (strcmp_safe(correct_name
, p
) != 0) {
536 printf("incorrect basename in all_info/fname - '%s'\n",
537 s1
->all_info
.out
.fname
.s
);
541 if (wire_bad_flags(&s1
->all_info
.out
.fname
, STR_UNICODE
, tree
->session
->transport
)) {
542 printf("Should not null terminate all_info/fname\n");
547 s1
= fnum_find("ALT_NAME_INFO");
549 correct_name
= s1
->alt_name_info
.out
.fname
.s
;
550 printf("alt_name: %s\n", correct_name
);
552 NAME_CHECK("ALT_NAME_INFO", alt_name_info
, fname
, STR_UNICODE
);
553 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info
, fname
, STR_UNICODE
);
555 /* and make sure we can open by alternate name */
556 smbcli_close(tree
, fnum
);
557 fnum
= smbcli_nt_create_full(tree
, correct_name
, 0,
559 FILE_ATTRIBUTE_NORMAL
,
560 NTCREATEX_SHARE_ACCESS_DELETE
|
561 NTCREATEX_SHARE_ACCESS_READ
|
562 NTCREATEX_SHARE_ACCESS_WRITE
,
563 NTCREATEX_DISP_OVERWRITE_IF
,
566 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree
));
571 correct_name
= "::$DATA";
572 printf("stream_name: %s\n", correct_name
);
574 NAME_CHECK("STREAM_INFO", stream_info
, streams
[0].stream_name
, STR_UNICODE
);
575 NAME_CHECK("STREAM_INFORMATION", stream_info
, streams
[0].stream_name
, STR_UNICODE
);
579 /* make sure the EAs look right */
580 s1
= fnum_find("ALL_EAS");
581 s2
= fnum_find("ALL_INFO");
583 for (i
=0;i
<s1
->all_eas
.out
.num_eas
;i
++) {
584 printf(" flags=%d %s=%*.*s\n",
585 s1
->all_eas
.out
.eas
[i
].flags
,
586 s1
->all_eas
.out
.eas
[i
].name
.s
,
587 (int)s1
->all_eas
.out
.eas
[i
].value
.length
,
588 (int)s1
->all_eas
.out
.eas
[i
].value
.length
,
589 s1
->all_eas
.out
.eas
[i
].value
.data
);
593 if (s1
->all_eas
.out
.num_eas
== 0) {
594 if (s2
->all_info
.out
.ea_size
!= 0) {
595 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
596 s2
->all_info
.out
.ea_size
);
599 if (s2
->all_info
.out
.ea_size
!=
600 ea_list_size(s1
->all_eas
.out
.num_eas
, s1
->all_eas
.out
.eas
)) {
601 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
602 (int)ea_list_size(s1
->all_eas
.out
.num_eas
, s1
->all_eas
.out
.eas
),
603 (int)s2
->all_info
.out
.ea_size
);
607 s2
= fname_find("ALL_EAS");
609 VAL_EQUAL(all_eas
, num_eas
, all_eas
, num_eas
);
610 for (i
=0;i
<s1
->all_eas
.out
.num_eas
;i
++) {
611 VAL_EQUAL(all_eas
, eas
[i
].flags
, all_eas
, eas
[i
].flags
);
612 STR_EQUAL(all_eas
, eas
[i
].name
, all_eas
, eas
[i
].name
);
613 VAL_EQUAL(all_eas
, eas
[i
].value
.length
, all_eas
, eas
[i
].value
.length
);
617 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
618 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
619 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
620 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
621 #stype1, #tfield1, #stype2, #tfield2, \
622 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
625 s1 = fname_find(sname1); s2 = fname_find(sname2); \
626 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
627 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
628 #stype1, #tfield1, #stype2, #tfield2, \
629 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
632 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
633 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
634 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
635 #stype1, #tfield1, #stype2, #tfield2, \
636 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
639 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
640 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
641 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
642 #stype1, #tfield1, #stype2, #tfield2, \
643 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
647 VAL_CHECK("STANDARD_INFO", standard_info
, delete_pending
,
648 "ALL_INFO", all_info
, delete_pending
);
649 VAL_CHECK("STANDARD_INFO", standard_info
, directory
,
650 "ALL_INFO", all_info
, directory
);
651 VAL_CHECK("STANDARD_INFO", standard_info
, nlink
,
652 "ALL_INFO", all_info
, nlink
);
653 VAL_CHECK("EA_INFO", ea_info
, ea_size
,
654 "ALL_INFO", all_info
, ea_size
);
655 VAL_CHECK("EA_SIZE", ea_size
, ea_size
,
656 "ALL_INFO", all_info
, ea_size
);
659 #define NAME_PATH_CHECK(sname, stype, field) do { \
660 s1 = fname_find(sname); s2 = fnum_find(sname); \
662 VAL_EQUAL(stype, field, stype, field); \
667 s1
= fnum_find("INTERNAL_INFORMATION");
669 printf("file_id=%.0f\n", (double)s1
->internal_information
.out
.file_id
);
672 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information
, file_id
);
673 NAME_PATH_CHECK("POSITION_INFORMATION", position_information
, position
);
675 printf("fnum pos = %.0f, fname pos = %.0f\n",
676 (double)s2
->position_information
.out
.position
,
677 (double)s1
->position_information
.out
.position
);
679 NAME_PATH_CHECK("MODE_INFORMATION", mode_information
, mode
);
680 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information
, alignment_requirement
);
681 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, attrib
);
682 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information
, reparse_tag
);
685 /* these are expected to differ */
686 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information
, access_flags
);
690 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
691 s1 = fnum_find(sname); \
692 if (s1 && s1->stype.out.tfield != 0) { \
693 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
695 (uint_t)s1->stype.out.tfield); \
697 s1 = fname_find(sname); \
698 if (s1 && s1->stype.out.tfield != 0) { \
699 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
701 (uint_t)s1->stype.out.tfield); \
704 /* now get a bit fancier .... */
706 /* when we set the delete disposition then the link count should drop
707 to 0 and delete_pending should be 1 */
715 /* basic testing of all RAW_FILEINFO_* calls
716 for each call we test that it succeeds, and where possible test
717 for consistency between the calls.
719 BOOL
torture_raw_qfileinfo(struct torture_context
*torture
)
721 struct smbcli_state
*cli
;
725 const char *fname
= "\\torture_qfileinfo.txt";
729 if (!torture_open_connection(&cli
, 0)) {
733 mem_ctx
= talloc_init("torture_qfileinfo");
735 fnum
= create_complex_file(cli
, mem_ctx
, fname
);
737 printf("ERROR: open of %s failed (%s)\n", fname
, smbcli_errstr(cli
->tree
));
742 ret
= torture_raw_qfileinfo_internals(torture
, mem_ctx
, cli
->tree
, fnum
, fname
);
744 smbcli_close(cli
->tree
, fnum
);
745 smbcli_unlink(cli
->tree
, fname
);
748 torture_close_connection(cli
);
749 talloc_free(mem_ctx
);
753 BOOL
torture_raw_qfileinfo_pipe(struct torture_context
*torture
)
758 const char *fname
= "\\lsass";
759 struct smbcli_state
*cli
;
760 struct dcerpc_pipe
*p
;
761 struct smbcli_tree
*ipc_tree
;
766 if (!torture_open_connection(&cli
, 0)) {
770 mem_ctx
= talloc_init("torture_qfileinfo_pipe");
772 if (!(p
= dcerpc_pipe_init(mem_ctx
,
773 cli
->tree
->session
->transport
->socket
->event
.ctx
))) {
777 status
= dcerpc_pipe_open_smb(p
, cli
->tree
, fname
);
778 if (!NT_STATUS_IS_OK(status
)) {
779 d_printf("dcerpc_pipe_open_smb failed: %s\n",
785 ipc_tree
= dcerpc_smb_tree(p
->conn
);
786 fnum
= dcerpc_smb_fnum(p
->conn
);
788 ret
= torture_raw_qfileinfo_internals(torture
, mem_ctx
, ipc_tree
, fnum
, fname
);