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, TALLOC_CTX *mem_ctx,
226 struct smbcli_tree *tree, int fnum, const char *fname,
232 union smb_fileinfo *s1, *s2;
234 uint64_t correct_size;
235 uint32_t correct_attrib;
236 const char *correct_name;
237 BOOL skip_streams = False;
239 /* scan all the fileinfo and pathinfo levels */
240 for (i=0; levels[i].name; i++) {
241 if (!levels[i].only_paths) {
242 levels[i].fnum_finfo.generic.level = levels[i].level;
243 levels[i].fnum_finfo.generic.in.file.fnum = fnum;
244 levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx,
245 &levels[i].fnum_finfo);
248 if (!levels[i].only_handles) {
249 levels[i].fname_finfo.generic.level = levels[i].level;
250 levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
251 levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx,
252 &levels[i].fname_finfo);
256 /* check for completely broken levels */
257 for (count=i=0; levels[i].name; i++) {
258 uint32_t cap = tree->session->transport->negotiate.capabilities;
259 /* see if this server claims to support this level */
260 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
265 if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
266 } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
267 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n",
268 levels[i].name, nt_errstr(levels[i].fname_status));
271 if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
272 printf("ERROR: fnum level %s failed, expected %s - %s\n",
273 levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status),
274 nt_errstr(levels[i].fnum_status));
278 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
279 printf("ERROR: fnum level %s failed - %s\n",
280 levels[i].name, nt_errstr(levels[i].fnum_status));
283 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
284 printf("ERROR: fname level %s failed - %s\n",
285 levels[i].name, nt_errstr(levels[i].fname_status));
294 printf("%d levels failed\n", count);
296 printf("too many level failures - giving up\n");
301 /* see if we can do streams */
302 s1 = fnum_find("STREAM_INFO");
303 if (!s1 || s1->stream_info.out.num_streams == 0) {
305 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
306 s1 ? s1->stream_info.out.num_streams : -1);
312 /* this code is incredibly repititive but doesn't lend itself to loops, so
313 we use lots of macros to make it less painful */
315 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
316 this code to fail, but we need to check it for completeness */
320 #define ALIAS_CHECK(sname1, sname2) \
322 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
323 if (s1 && s2) { INFO_CHECK } \
324 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
325 if (s1 && s2) { INFO_CHECK } \
326 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
327 if (s1 && s2) { INFO_CHECK } \
331 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
332 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
333 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
334 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
335 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
337 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
341 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
342 VAL_EQUAL(standard_info, size, standard_info, size); \
343 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
344 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
345 VAL_EQUAL(standard_info, directory, standard_info, directory);
347 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
351 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
353 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
357 STR_EQUAL(name_info, fname, name_info, fname);
359 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
363 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
364 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
365 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
366 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
367 VAL_EQUAL(all_info, attrib, all_info, attrib); \
368 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
369 VAL_EQUAL(all_info, size, all_info, size); \
370 VAL_EQUAL(all_info, nlink, all_info, nlink); \
371 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
372 VAL_EQUAL(all_info, directory, all_info, directory); \
373 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
374 STR_EQUAL(all_info, fname, all_info, fname);
376 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
380 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
381 VAL_EQUAL(compression_info, format, compression_info, format); \
382 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
383 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
384 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
386 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
391 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
393 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
396 #define TIME_CHECK_NT(sname, stype, tfield) do { \
397 s1 = fnum_find(sname); \
398 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
399 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
400 nt_time_string(mem_ctx, s1->stype.out.tfield), \
401 nt_time_string(mem_ctx, correct_time)); \
404 s1 = fname_find(is_ipc, sname); \
405 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
406 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
407 nt_time_string(mem_ctx, s1->stype.out.tfield), \
408 nt_time_string(mem_ctx, correct_time)); \
412 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
413 s1 = fnum_find(sname); \
414 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
415 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
416 timestring(mem_ctx, s1->stype.out.tfield), \
417 nt_time_string(mem_ctx, correct_time)); \
420 s1 = fname_find(is_ipc, sname); \
421 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
422 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
423 timestring(mem_ctx, s1->stype.out.tfield), \
424 nt_time_string(mem_ctx, correct_time)); \
429 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
430 s1 = fnum_find(sname); \
431 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
432 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
433 timestring(mem_ctx, s1->stype.out.tfield), \
434 nt_time_string(mem_ctx, correct_time)); \
437 s1 = fname_find(is_ipc, sname); \
438 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
439 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
440 timestring(mem_ctx, s1->stype.out.tfield), \
441 nt_time_string(mem_ctx, correct_time)); \
446 /* now check that all the times that are supposed to be equal are correct */
447 s1 = fnum_find("BASIC_INFO");
448 correct_time = s1->basic_info.out.create_time;
449 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
451 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
452 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
453 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
454 TIME_CHECK_DOS("STANDARD", standard, create_time);
455 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
456 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
457 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
459 s1 = fnum_find("BASIC_INFO");
460 correct_time = s1->basic_info.out.access_time;
461 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
463 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
464 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
465 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
466 TIME_CHECK_DOS("STANDARD", standard, access_time);
467 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
468 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
469 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
471 s1 = fnum_find("BASIC_INFO");
472 correct_time = s1->basic_info.out.write_time;
473 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
475 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
476 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
477 TIME_CHECK_DOS("GETATTR", getattr, write_time);
478 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
479 TIME_CHECK_DOS("STANDARD", standard, write_time);
480 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
481 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
482 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
484 s1 = fnum_find("BASIC_INFO");
485 correct_time = s1->basic_info.out.change_time;
486 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
488 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
489 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
490 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
491 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
494 #define SIZE_CHECK(sname, stype, tfield) do { \
495 s1 = fnum_find(sname); \
496 if (s1 && s1->stype.out.tfield != correct_size) { \
497 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
498 (uint_t)s1->stype.out.tfield, \
499 (uint_t)correct_size); \
502 s1 = fname_find(is_ipc, sname); \
503 if (s1 && s1->stype.out.tfield != correct_size) { \
504 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
505 (uint_t)s1->stype.out.tfield, \
506 (uint_t)correct_size); \
510 s1 = fnum_find("STANDARD_INFO");
511 correct_size = s1->standard_info.out.size;
512 printf("size: %u\n", (uint_t)correct_size);
514 SIZE_CHECK("GETATTR", getattr, size);
515 SIZE_CHECK("GETATTRE", getattre, size);
516 SIZE_CHECK("STANDARD", standard, size);
517 SIZE_CHECK("EA_SIZE", ea_size, size);
518 SIZE_CHECK("STANDARD_INFO", standard_info, size);
519 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
520 SIZE_CHECK("ALL_INFO", all_info, size);
521 SIZE_CHECK("ALL_INFORMATION", all_info, size);
522 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
523 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
524 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
526 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
527 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
531 s1 = fnum_find("STANDARD_INFO");
532 correct_size = s1->standard_info.out.alloc_size;
533 printf("alloc_size: %u\n", (uint_t)correct_size);
535 SIZE_CHECK("GETATTRE", getattre, alloc_size);
536 SIZE_CHECK("STANDARD", standard, alloc_size);
537 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
538 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
539 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
540 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
541 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
542 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
544 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
545 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
548 #define ATTRIB_CHECK(sname, stype, tfield) do { \
549 s1 = fnum_find(sname); \
550 if (s1 && s1->stype.out.tfield != correct_attrib) { \
551 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
552 (uint_t)s1->stype.out.tfield, \
553 (uint_t)correct_attrib); \
556 s1 = fname_find(is_ipc, sname); \
557 if (s1 && s1->stype.out.tfield != correct_attrib) { \
558 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
559 (uint_t)s1->stype.out.tfield, \
560 (uint_t)correct_attrib); \
564 s1 = fnum_find("BASIC_INFO");
565 correct_attrib = s1->basic_info.out.attrib;
566 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
568 ATTRIB_CHECK("GETATTR", getattr, attrib);
570 ATTRIB_CHECK("GETATTRE", getattre, attrib);
571 ATTRIB_CHECK("STANDARD", standard, attrib);
572 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
574 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
575 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
576 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
577 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
578 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
579 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
581 correct_name = fname;
582 printf("name: %s\n", correct_name);
584 #define NAME_CHECK(sname, stype, tfield, flags) do { \
585 s1 = fnum_find(sname); \
586 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
587 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
588 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
589 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
592 s1 = fname_find(is_ipc, sname); \
593 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
594 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
595 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
596 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
600 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
601 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
603 /* the ALL_INFO file name is the full path on the filesystem */
604 s1 = fnum_find("ALL_INFO");
605 if (s1 && !s1->all_info.out.fname.s) {
606 printf("ALL_INFO didn't give a filename\n");
609 if (s1 && s1->all_info.out.fname.s) {
610 char *p = strrchr(s1->all_info.out.fname.s, '\\');
612 printf("Not a full path in all_info/fname? - '%s'\n",
613 s1->all_info.out.fname.s);
616 if (strcmp_safe(correct_name, p) != 0) {
617 printf("incorrect basename in all_info/fname - '%s'\n",
618 s1->all_info.out.fname.s);
622 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
623 printf("Should not null terminate all_info/fname\n");
628 s1 = fnum_find("ALT_NAME_INFO");
630 correct_name = s1->alt_name_info.out.fname.s;
631 printf("alt_name: %s\n", correct_name);
633 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
634 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
636 /* and make sure we can open by alternate name */
637 smbcli_close(tree, fnum);
638 fnum = smbcli_nt_create_full(tree, correct_name, 0,
640 FILE_ATTRIBUTE_NORMAL,
641 NTCREATEX_SHARE_ACCESS_DELETE|
642 NTCREATEX_SHARE_ACCESS_READ|
643 NTCREATEX_SHARE_ACCESS_WRITE,
644 NTCREATEX_DISP_OVERWRITE_IF,
647 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
652 correct_name = "::$DATA";
653 printf("stream_name: %s\n", correct_name);
655 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
656 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
660 /* make sure the EAs look right */
661 s1 = fnum_find("ALL_EAS");
662 s2 = fnum_find("ALL_INFO");
664 for (i=0;i<s1->all_eas.out.num_eas;i++) {
665 printf(" flags=%d %s=%*.*s\n",
666 s1->all_eas.out.eas[i].flags,
667 s1->all_eas.out.eas[i].name.s,
668 (int)s1->all_eas.out.eas[i].value.length,
669 (int)s1->all_eas.out.eas[i].value.length,
670 s1->all_eas.out.eas[i].value.data);
674 if (s1->all_eas.out.num_eas == 0) {
675 if (s2->all_info.out.ea_size != 0) {
676 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
677 s2->all_info.out.ea_size);
680 if (s2->all_info.out.ea_size !=
681 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
682 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
683 (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
684 (int)s2->all_info.out.ea_size);
688 s2 = fname_find(is_ipc, "ALL_EAS");
690 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
691 for (i=0;i<s1->all_eas.out.num_eas;i++) {
692 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
693 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
694 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
698 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
699 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
700 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
701 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
702 #stype1, #tfield1, #stype2, #tfield2, \
703 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
706 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
707 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
708 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
709 #stype1, #tfield1, #stype2, #tfield2, \
710 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
713 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
714 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
715 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
716 #stype1, #tfield1, #stype2, #tfield2, \
717 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
720 s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
721 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
722 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
723 #stype1, #tfield1, #stype2, #tfield2, \
724 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
728 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
729 "ALL_INFO", all_info, delete_pending);
730 VAL_CHECK("STANDARD_INFO", standard_info, directory,
731 "ALL_INFO", all_info, directory);
732 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
733 "ALL_INFO", all_info, nlink);
734 s1 = fnum_find("BASIC_INFO");
736 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
737 printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
741 s1 = fnum_find("STANDARD_INFO");
743 if (s1->standard_info.out.nlink != 1) {
744 printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
747 if (s1->standard_info.out.delete_pending != 1) {
748 printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
752 VAL_CHECK("EA_INFO", ea_info, ea_size,
753 "ALL_INFO", all_info, ea_size);
755 VAL_CHECK("EA_SIZE", ea_size, ea_size,
756 "ALL_INFO", all_info, ea_size);
759 #define NAME_PATH_CHECK(sname, stype, field) do { \
760 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
762 VAL_EQUAL(stype, field, stype, field); \
767 s1 = fnum_find("INTERNAL_INFORMATION");
769 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
772 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
773 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
775 printf("fnum pos = %.0f, fname pos = %.0f\n",
776 (double)s2->position_information.out.position,
777 (double)s1->position_information.out.position );
779 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
780 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
781 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
782 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
785 /* these are expected to differ */
786 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
790 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
791 s1 = fnum_find(sname); \
792 if (s1 && s1->stype.out.tfield != 0) { \
793 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
795 (uint_t)s1->stype.out.tfield); \
797 s1 = fname_find(is_ipc, sname); \
798 if (s1 && s1->stype.out.tfield != 0) { \
799 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
801 (uint_t)s1->stype.out.tfield); \
804 /* now get a bit fancier .... */
806 /* when we set the delete disposition then the link count should drop
807 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)
821 struct smbcli_state *cli;
825 const char *fname = "\\torture_qfileinfo.txt";
827 if (!torture_open_connection(&cli, 0)) {
831 mem_ctx = talloc_init("torture_qfileinfo");
833 fnum = create_complex_file(cli, mem_ctx, fname);
835 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
840 ret = torture_raw_qfileinfo_internals(torture, mem_ctx, cli->tree, fnum, fname, False /* is_ipc */);
842 smbcli_close(cli->tree, fnum);
843 smbcli_unlink(cli->tree, fname);
846 torture_close_connection(cli);
847 talloc_free(mem_ctx);
851 BOOL torture_raw_qfileinfo_pipe(struct torture_context *torture)
856 const char *fname = "\\lsass";
857 struct smbcli_state *cli;
858 struct dcerpc_pipe *p;
859 struct smbcli_tree *ipc_tree;
862 if (!torture_open_connection(&cli, 0)) {
866 mem_ctx = talloc_init("torture_qfileinfo_pipe");
868 if (!(p = dcerpc_pipe_init(mem_ctx,
869 cli->tree->session->transport->socket->event.ctx))) {
873 status = dcerpc_pipe_open_smb(p, cli->tree, fname);
874 if (!NT_STATUS_IS_OK(status)) {
875 d_printf("dcerpc_pipe_open_smb failed: %s\n",
881 ipc_tree = dcerpc_smb_tree(p->conn);
882 fnum = dcerpc_smb_fnum(p->conn);
884 ret = torture_raw_qfileinfo_internals(torture, mem_ctx, ipc_tree, fnum, fname, True /* is_ipc */);