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/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 uint_t 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;
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, (uint_t)s1->n1.out.v1, \
186 #n2, #v2, (uint_t)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 (uint_t)s1->n1.out.v1, \
215 (uint_t)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 && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
269 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n",
270 levels[i].name, nt_errstr(levels[i].fname_status));
273 if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
274 printf("ERROR: fnum level %s failed, expected %s - %s\n",
275 levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status),
276 nt_errstr(levels[i].fnum_status));
280 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
281 printf("ERROR: fnum level %s failed - %s\n",
282 levels[i].name, nt_errstr(levels[i].fnum_status));
285 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
286 printf("ERROR: fname level %s failed - %s\n",
287 levels[i].name, nt_errstr(levels[i].fname_status));
296 printf("%d levels failed\n", count);
298 printf("too many level failures - giving up\n");
303 /* see if we can do streams */
304 s1 = fnum_find("STREAM_INFO");
305 if (!s1 || s1->stream_info.out.num_streams == 0) {
307 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
308 s1 ? s1->stream_info.out.num_streams : -1);
314 /* this code is incredibly repititive but doesn't lend itself to loops, so
315 we use lots of macros to make it less painful */
317 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
318 this code to fail, but we need to check it for completeness */
322 #define ALIAS_CHECK(sname1, sname2) \
324 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
325 if (s1 && s2) { INFO_CHECK } \
326 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
327 if (s1 && s2) { INFO_CHECK } \
328 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
329 if (s1 && s2) { INFO_CHECK } \
333 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
334 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
335 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
336 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
337 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
339 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
343 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
344 VAL_EQUAL(standard_info, size, standard_info, size); \
345 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
346 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
347 VAL_EQUAL(standard_info, directory, standard_info, directory);
349 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
353 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
355 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
359 STR_EQUAL(name_info, fname, name_info, fname);
361 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
365 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
366 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
367 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
368 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
369 VAL_EQUAL(all_info, attrib, all_info, attrib); \
370 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
371 VAL_EQUAL(all_info, size, all_info, size); \
372 VAL_EQUAL(all_info, nlink, all_info, nlink); \
373 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
374 VAL_EQUAL(all_info, directory, all_info, directory); \
375 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
376 STR_EQUAL(all_info, fname, all_info, fname);
378 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
382 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
383 VAL_EQUAL(compression_info, format, compression_info, format); \
384 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
385 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
386 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
388 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
393 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
395 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
398 #define TIME_CHECK_NT(sname, stype, tfield) do { \
399 s1 = fnum_find(sname); \
400 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
401 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
402 nt_time_string(mem_ctx, s1->stype.out.tfield), \
403 nt_time_string(mem_ctx, correct_time)); \
406 s1 = fname_find(is_ipc, sname); \
407 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
408 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
409 nt_time_string(mem_ctx, s1->stype.out.tfield), \
410 nt_time_string(mem_ctx, correct_time)); \
414 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
415 s1 = fnum_find(sname); \
416 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
417 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
418 timestring(mem_ctx, s1->stype.out.tfield), \
419 nt_time_string(mem_ctx, correct_time)); \
422 s1 = fname_find(is_ipc, sname); \
423 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
424 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
425 timestring(mem_ctx, s1->stype.out.tfield), \
426 nt_time_string(mem_ctx, correct_time)); \
431 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
432 s1 = fnum_find(sname); \
433 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
434 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
435 timestring(mem_ctx, s1->stype.out.tfield), \
436 nt_time_string(mem_ctx, correct_time)); \
439 s1 = fname_find(is_ipc, sname); \
440 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
441 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
442 timestring(mem_ctx, s1->stype.out.tfield), \
443 nt_time_string(mem_ctx, correct_time)); \
448 /* now check that all the times that are supposed to be equal are correct */
449 s1 = fnum_find("BASIC_INFO");
450 correct_time = s1->basic_info.out.create_time;
451 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
453 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
454 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
455 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
456 TIME_CHECK_DOS("STANDARD", standard, create_time);
457 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
458 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
459 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
461 s1 = fnum_find("BASIC_INFO");
462 correct_time = s1->basic_info.out.access_time;
463 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
465 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
466 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
467 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
468 TIME_CHECK_DOS("STANDARD", standard, access_time);
469 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
470 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
471 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
473 s1 = fnum_find("BASIC_INFO");
474 correct_time = s1->basic_info.out.write_time;
475 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
477 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
478 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
479 TIME_CHECK_DOS("GETATTR", getattr, write_time);
480 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
481 TIME_CHECK_DOS("STANDARD", standard, write_time);
482 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
483 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
484 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
486 s1 = fnum_find("BASIC_INFO");
487 correct_time = s1->basic_info.out.change_time;
488 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
490 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
491 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
492 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
493 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
496 #define SIZE_CHECK(sname, stype, tfield) do { \
497 s1 = fnum_find(sname); \
498 if (s1 && s1->stype.out.tfield != correct_size) { \
499 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
500 (uint_t)s1->stype.out.tfield, \
501 (uint_t)correct_size); \
504 s1 = fname_find(is_ipc, sname); \
505 if (s1 && s1->stype.out.tfield != correct_size) { \
506 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
507 (uint_t)s1->stype.out.tfield, \
508 (uint_t)correct_size); \
512 s1 = fnum_find("STANDARD_INFO");
513 correct_size = s1->standard_info.out.size;
514 printf("size: %u\n", (uint_t)correct_size);
516 SIZE_CHECK("GETATTR", getattr, size);
517 SIZE_CHECK("GETATTRE", getattre, size);
518 SIZE_CHECK("STANDARD", standard, size);
519 SIZE_CHECK("EA_SIZE", ea_size, size);
520 SIZE_CHECK("STANDARD_INFO", standard_info, size);
521 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
522 SIZE_CHECK("ALL_INFO", all_info, size);
523 SIZE_CHECK("ALL_INFORMATION", all_info, size);
524 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
525 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
526 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
528 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
529 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
533 s1 = fnum_find("STANDARD_INFO");
534 correct_size = s1->standard_info.out.alloc_size;
535 printf("alloc_size: %u\n", (uint_t)correct_size);
537 SIZE_CHECK("GETATTRE", getattre, alloc_size);
538 SIZE_CHECK("STANDARD", standard, alloc_size);
539 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
540 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
541 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
542 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
543 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
544 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
546 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
547 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
550 #define ATTRIB_CHECK(sname, stype, tfield) do { \
551 s1 = fnum_find(sname); \
552 if (s1 && s1->stype.out.tfield != correct_attrib) { \
553 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
554 (uint_t)s1->stype.out.tfield, \
555 (uint_t)correct_attrib); \
558 s1 = fname_find(is_ipc, sname); \
559 if (s1 && s1->stype.out.tfield != correct_attrib) { \
560 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
561 (uint_t)s1->stype.out.tfield, \
562 (uint_t)correct_attrib); \
566 s1 = fnum_find("BASIC_INFO");
567 correct_attrib = s1->basic_info.out.attrib;
568 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
570 ATTRIB_CHECK("GETATTR", getattr, attrib);
572 ATTRIB_CHECK("GETATTRE", getattre, attrib);
573 ATTRIB_CHECK("STANDARD", standard, attrib);
574 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
576 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
577 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
578 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
579 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
580 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
581 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
583 correct_name = fname;
584 printf("name: %s\n", correct_name);
586 #define NAME_CHECK(sname, stype, tfield, flags) do { \
587 s1 = fnum_find(sname); \
588 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
589 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
590 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
591 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
594 s1 = fname_find(is_ipc, sname); \
595 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
596 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
597 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
598 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
602 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
603 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
605 /* the ALL_INFO file name is the full path on the filesystem */
606 s1 = fnum_find("ALL_INFO");
607 if (s1 && !s1->all_info.out.fname.s) {
608 printf("ALL_INFO didn't give a filename\n");
611 if (s1 && s1->all_info.out.fname.s) {
612 char *p = strrchr(s1->all_info.out.fname.s, '\\');
614 printf("Not a full path in all_info/fname? - '%s'\n",
615 s1->all_info.out.fname.s);
618 if (strcmp_safe(correct_name, p) != 0) {
619 printf("incorrect basename in all_info/fname - '%s'\n",
620 s1->all_info.out.fname.s);
624 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
625 printf("Should not null terminate all_info/fname\n");
630 s1 = fnum_find("ALT_NAME_INFO");
632 correct_name = s1->alt_name_info.out.fname.s;
633 printf("alt_name: %s\n", correct_name);
635 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
636 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
638 /* and make sure we can open by alternate name */
639 smbcli_close(tree, fnum);
640 fnum = smbcli_nt_create_full(tree, correct_name, 0,
642 FILE_ATTRIBUTE_NORMAL,
643 NTCREATEX_SHARE_ACCESS_DELETE|
644 NTCREATEX_SHARE_ACCESS_READ|
645 NTCREATEX_SHARE_ACCESS_WRITE,
646 NTCREATEX_DISP_OVERWRITE_IF,
649 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
654 correct_name = "::$DATA";
655 printf("stream_name: %s\n", correct_name);
657 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
658 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
662 /* make sure the EAs look right */
663 s1 = fnum_find("ALL_EAS");
664 s2 = fnum_find("ALL_INFO");
666 for (i=0;i<s1->all_eas.out.num_eas;i++) {
667 printf(" flags=%d %s=%*.*s\n",
668 s1->all_eas.out.eas[i].flags,
669 s1->all_eas.out.eas[i].name.s,
670 (int)s1->all_eas.out.eas[i].value.length,
671 (int)s1->all_eas.out.eas[i].value.length,
672 s1->all_eas.out.eas[i].value.data);
676 if (s1->all_eas.out.num_eas == 0) {
677 if (s2->all_info.out.ea_size != 0) {
678 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
679 s2->all_info.out.ea_size);
682 if (s2->all_info.out.ea_size !=
683 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
684 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
685 (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
686 (int)s2->all_info.out.ea_size);
690 s2 = fname_find(is_ipc, "ALL_EAS");
692 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
693 for (i=0;i<s1->all_eas.out.num_eas;i++) {
694 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
695 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
696 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
700 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
701 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
702 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
703 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
704 #stype1, #tfield1, #stype2, #tfield2, \
705 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
708 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
709 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
710 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
711 #stype1, #tfield1, #stype2, #tfield2, \
712 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
715 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
716 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
717 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
718 #stype1, #tfield1, #stype2, #tfield2, \
719 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
722 s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
723 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
724 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
725 #stype1, #tfield1, #stype2, #tfield2, \
726 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
730 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
731 "ALL_INFO", all_info, delete_pending);
732 VAL_CHECK("STANDARD_INFO", standard_info, directory,
733 "ALL_INFO", all_info, directory);
734 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
735 "ALL_INFO", all_info, nlink);
736 s1 = fnum_find("BASIC_INFO");
738 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
739 printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
743 s1 = fnum_find("STANDARD_INFO");
745 if (s1->standard_info.out.nlink != 1) {
746 printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
749 if (s1->standard_info.out.delete_pending != 1) {
750 printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
754 VAL_CHECK("EA_INFO", ea_info, ea_size,
755 "ALL_INFO", all_info, ea_size);
757 VAL_CHECK("EA_SIZE", ea_size, ea_size,
758 "ALL_INFO", all_info, ea_size);
761 #define NAME_PATH_CHECK(sname, stype, field) do { \
762 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
764 VAL_EQUAL(stype, field, stype, field); \
769 s1 = fnum_find("INTERNAL_INFORMATION");
771 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
774 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
775 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
777 printf("fnum pos = %.0f, fname pos = %.0f\n",
778 (double)s2->position_information.out.position,
779 (double)s1->position_information.out.position );
781 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
782 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
783 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
784 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
787 /* these are expected to differ */
788 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
792 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
793 s1 = fnum_find(sname); \
794 if (s1 && s1->stype.out.tfield != 0) { \
795 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
797 (uint_t)s1->stype.out.tfield); \
799 s1 = fname_find(is_ipc, sname); \
800 if (s1 && s1->stype.out.tfield != 0) { \
801 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
803 (uint_t)s1->stype.out.tfield); \
806 /* now get a bit fancier .... */
808 /* when we set the delete disposition then the link count should drop
809 to 0 and delete_pending should be 1 */
817 /* basic testing of all RAW_FILEINFO_* calls
818 for each call we test that it succeeds, and where possible test
819 for consistency between the calls.
821 bool torture_raw_qfileinfo(struct torture_context *torture,
822 struct smbcli_state *cli)
826 const char *fname = "\\torture_qfileinfo.txt";
828 fnum = create_complex_file(cli, torture, fname);
830 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
834 ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, False /* is_ipc */);
836 smbcli_close(cli->tree, fnum);
837 smbcli_unlink(cli->tree, fname);
842 bool torture_raw_qfileinfo_pipe(struct torture_context *torture,
843 struct smbcli_state *cli)
847 const char *fname = "\\lsass";
848 struct dcerpc_pipe *p;
849 struct smbcli_tree *ipc_tree;
852 if (!(p = dcerpc_pipe_init(torture,
853 cli->tree->session->transport->socket->event.ctx))) {
857 status = dcerpc_pipe_open_smb(p, cli->tree, fname);
858 if (!NT_STATUS_IS_OK(status)) {
859 d_printf("dcerpc_pipe_open_smb failed: %s\n",
865 ipc_tree = dcerpc_smb_tree(p->conn);
866 fnum = dcerpc_smb_fnum(p->conn);
868 ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, True /* is_ipc */);