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"
28 #include "torture/raw/proto.h"
29 #include "param/param.h"
33 enum smb_fileinfo_level level;
35 uint_t only_handles:1;
36 uint32_t capability_mask;
37 uint_t expected_ipc_access_denied:1;
38 NTSTATUS expected_ipc_fnum_status;
39 NTSTATUS fnum_status, fname_status;
40 union smb_fileinfo fnum_finfo, fname_finfo;
43 .level = RAW_FILEINFO_GETATTR,
46 .expected_ipc_access_denied = 1},
48 .level = RAW_FILEINFO_GETATTRE,
52 .level = RAW_FILEINFO_STANDARD, },
54 .level = RAW_FILEINFO_EA_SIZE },
56 .level = RAW_FILEINFO_ALL_EAS,
57 .expected_ipc_fnum_status = NT_STATUS_ACCESS_DENIED,
59 { .name ="IS_NAME_VALID",
60 .level = RAW_FILEINFO_IS_NAME_VALID,
63 { .name ="BASIC_INFO",
64 .level = RAW_FILEINFO_BASIC_INFO },
65 { .name ="STANDARD_INFO",
66 .level = RAW_FILEINFO_STANDARD_INFO },
68 .level = RAW_FILEINFO_EA_INFO },
70 .level = RAW_FILEINFO_NAME_INFO },
72 .level = RAW_FILEINFO_ALL_INFO },
73 { .name ="ALT_NAME_INFO",
74 .level = RAW_FILEINFO_ALT_NAME_INFO,
75 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
77 { .name ="STREAM_INFO",
78 .level = RAW_FILEINFO_STREAM_INFO,
79 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
81 { .name ="COMPRESSION_INFO",
82 .level = RAW_FILEINFO_COMPRESSION_INFO,
83 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
85 { .name ="UNIX_BASIC_INFO",
86 .level = RAW_FILEINFO_UNIX_BASIC,
89 .capability_mask = CAP_UNIX},
90 { .name ="UNIX_LINK_INFO",
91 .level = RAW_FILEINFO_UNIX_LINK,
94 .capability_mask = CAP_UNIX},
95 { .name ="BASIC_INFORMATION",
96 .level = RAW_FILEINFO_BASIC_INFORMATION },
97 { .name ="STANDARD_INFORMATION",
98 .level = RAW_FILEINFO_STANDARD_INFORMATION },
99 { .name ="INTERNAL_INFORMATION",
100 .level = RAW_FILEINFO_INTERNAL_INFORMATION },
101 { .name ="EA_INFORMATION",
102 .level = RAW_FILEINFO_EA_INFORMATION },
103 { .name = "ACCESS_INFORMATION",
104 .level = RAW_FILEINFO_ACCESS_INFORMATION },
105 { .name = "NAME_INFORMATION",
106 .level = RAW_FILEINFO_NAME_INFORMATION },
107 { .name ="POSITION_INFORMATION",
108 .level = RAW_FILEINFO_POSITION_INFORMATION },
109 { .name ="MODE_INFORMATION",
110 .level = RAW_FILEINFO_MODE_INFORMATION },
111 { .name ="ALIGNMENT_INFORMATION",
112 .level = RAW_FILEINFO_ALIGNMENT_INFORMATION },
113 { .name ="ALL_INFORMATION",
114 .level = RAW_FILEINFO_ALL_INFORMATION },
115 { .name ="ALT_NAME_INFORMATION",
116 .level = RAW_FILEINFO_ALT_NAME_INFORMATION,
117 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
119 { .name ="STREAM_INFORMATION",
120 .level = RAW_FILEINFO_STREAM_INFORMATION,
121 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
123 { .name = "COMPRESSION_INFORMATION",
124 .level = RAW_FILEINFO_COMPRESSION_INFORMATION,
125 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
127 { .name ="NETWORK_OPEN_INFORMATION",
128 .level = RAW_FILEINFO_NETWORK_OPEN_INFORMATION,
129 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
131 { .name = "ATTRIBUTE_TAG_INFORMATION",
132 .level = RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION,
133 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
139 compare a dos time (2 second resolution) to a nt time
141 static int dos_nt_time_cmp(time_t t, NTTIME nt)
143 time_t t2 = nt_time_to_unix(nt);
144 if (abs(t2 - t) <= 2) return 0;
150 find a level in the levels[] table
152 static union smb_fileinfo *fnum_find(const char *name)
155 for (i=0; levels[i].name; i++) {
156 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
157 strcmp(name, levels[i].name) == 0 &&
158 !levels[i].only_paths) {
159 return &levels[i].fnum_finfo;
166 find a level in the levels[] table
168 static union smb_fileinfo *fname_find(bool is_ipc, const char *name)
174 for (i=0; levels[i].name; i++) {
175 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
176 strcmp(name, levels[i].name) == 0 &&
177 !levels[i].only_handles) {
178 return &levels[i].fname_finfo;
184 /* local macros to make the code below more readable */
185 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
186 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
187 #n1, #v1, (uint_t)s1->n1.out.v1, \
188 #n2, #v2, (uint_t)s2->n2.out.v2, \
189 __FILE__, __LINE__); \
193 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
194 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
195 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
196 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
197 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
198 __FILE__, __LINE__); \
202 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
203 printf("%s/%s != %s/%s at %s(%d)\n", \
206 __FILE__, __LINE__); \
210 /* used to find hints on unknown values - and to make sure
213 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
214 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
216 (uint_t)s1->n1.out.v1, \
217 (uint_t)s1->n1.out.v1, \
218 __FILE__, __LINE__); \
223 /* basic testing of all RAW_FILEINFO_* calls
224 for each call we test that it succeeds, and where possible test
225 for consistency between the calls.
227 static bool torture_raw_qfileinfo_internals(struct torture_context *torture,
229 struct smbcli_tree *tree,
230 int fnum, const char *fname,
236 union smb_fileinfo *s1, *s2;
238 uint64_t correct_size;
239 uint32_t correct_attrib;
240 const char *correct_name;
241 bool skip_streams = false;
243 /* scan all the fileinfo and pathinfo levels */
244 for (i=0; levels[i].name; i++) {
245 if (!levels[i].only_paths) {
246 levels[i].fnum_finfo.generic.level = levels[i].level;
247 levels[i].fnum_finfo.generic.in.file.fnum = fnum;
248 levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx,
249 &levels[i].fnum_finfo);
252 if (!levels[i].only_handles) {
253 levels[i].fname_finfo.generic.level = levels[i].level;
254 levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
255 levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx,
256 &levels[i].fname_finfo);
260 /* check for completely broken levels */
261 for (count=i=0; levels[i].name; i++) {
262 uint32_t cap = tree->session->transport->negotiate.capabilities;
263 /* see if this server claims to support this level */
264 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
269 if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
270 } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
271 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n",
272 levels[i].name, nt_errstr(levels[i].fname_status));
275 if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
276 printf("ERROR: fnum level %s failed, expected %s - %s\n",
277 levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status),
278 nt_errstr(levels[i].fnum_status));
282 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
283 printf("ERROR: fnum level %s failed - %s\n",
284 levels[i].name, nt_errstr(levels[i].fnum_status));
287 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
288 printf("ERROR: fname level %s failed - %s\n",
289 levels[i].name, nt_errstr(levels[i].fname_status));
298 printf("%d levels failed\n", count);
300 torture_fail(torture, "too many level failures - giving up");
304 /* see if we can do streams */
305 s1 = fnum_find("STREAM_INFO");
306 if (!s1 || s1->stream_info.out.num_streams == 0) {
308 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
309 s1 ? s1->stream_info.out.num_streams : -1);
315 /* this code is incredibly repititive but doesn't lend itself to loops, so
316 we use lots of macros to make it less painful */
318 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
319 this code to fail, but we need to check it for completeness */
323 #define ALIAS_CHECK(sname1, sname2) \
325 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
326 if (s1 && s2) { INFO_CHECK } \
327 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
328 if (s1 && s2) { INFO_CHECK } \
329 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
330 if (s1 && s2) { INFO_CHECK } \
334 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
335 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
336 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
337 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
338 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
340 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
344 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
345 VAL_EQUAL(standard_info, size, standard_info, size); \
346 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
347 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
348 VAL_EQUAL(standard_info, directory, standard_info, directory);
350 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
354 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
356 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
360 STR_EQUAL(name_info, fname, name_info, fname);
362 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
366 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
367 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
368 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
369 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
370 VAL_EQUAL(all_info, attrib, all_info, attrib); \
371 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
372 VAL_EQUAL(all_info, size, all_info, size); \
373 VAL_EQUAL(all_info, nlink, all_info, nlink); \
374 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
375 VAL_EQUAL(all_info, directory, all_info, directory); \
376 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
377 STR_EQUAL(all_info, fname, all_info, fname);
379 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
383 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
384 VAL_EQUAL(compression_info, format, compression_info, format); \
385 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
386 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
387 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
389 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
394 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
396 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
399 #define TIME_CHECK_NT(sname, stype, tfield) do { \
400 s1 = fnum_find(sname); \
401 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
402 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
403 nt_time_string(mem_ctx, s1->stype.out.tfield), \
404 nt_time_string(mem_ctx, correct_time)); \
407 s1 = fname_find(is_ipc, sname); \
408 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
409 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
410 nt_time_string(mem_ctx, s1->stype.out.tfield), \
411 nt_time_string(mem_ctx, correct_time)); \
415 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
416 s1 = fnum_find(sname); \
417 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
418 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
419 timestring(mem_ctx, s1->stype.out.tfield), \
420 nt_time_string(mem_ctx, correct_time)); \
423 s1 = fname_find(is_ipc, sname); \
424 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
425 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
426 timestring(mem_ctx, s1->stype.out.tfield), \
427 nt_time_string(mem_ctx, correct_time)); \
432 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
433 s1 = fnum_find(sname); \
434 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
435 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
436 timestring(mem_ctx, s1->stype.out.tfield), \
437 nt_time_string(mem_ctx, correct_time)); \
440 s1 = fname_find(is_ipc, sname); \
441 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
442 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
443 timestring(mem_ctx, s1->stype.out.tfield), \
444 nt_time_string(mem_ctx, correct_time)); \
449 /* now check that all the times that are supposed to be equal are correct */
450 s1 = fnum_find("BASIC_INFO");
451 correct_time = s1->basic_info.out.create_time;
452 torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time));
454 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
455 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
456 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
457 TIME_CHECK_DOS("STANDARD", standard, create_time);
458 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
459 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
460 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
462 s1 = fnum_find("BASIC_INFO");
463 correct_time = s1->basic_info.out.access_time;
464 torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time));
466 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
467 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
468 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
469 TIME_CHECK_DOS("STANDARD", standard, access_time);
470 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
471 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
472 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
474 s1 = fnum_find("BASIC_INFO");
475 correct_time = s1->basic_info.out.write_time;
476 torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time));
478 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
479 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
480 TIME_CHECK_DOS("GETATTR", getattr, write_time);
481 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
482 TIME_CHECK_DOS("STANDARD", standard, write_time);
483 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
484 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
485 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
487 s1 = fnum_find("BASIC_INFO");
488 correct_time = s1->basic_info.out.change_time;
489 torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time));
491 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
492 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
493 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
494 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
497 #define SIZE_CHECK(sname, stype, tfield) do { \
498 s1 = fnum_find(sname); \
499 if (s1 && s1->stype.out.tfield != correct_size) { \
500 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
501 (uint_t)s1->stype.out.tfield, \
502 (uint_t)correct_size); \
505 s1 = fname_find(is_ipc, sname); \
506 if (s1 && s1->stype.out.tfield != correct_size) { \
507 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
508 (uint_t)s1->stype.out.tfield, \
509 (uint_t)correct_size); \
513 s1 = fnum_find("STANDARD_INFO");
514 correct_size = s1->standard_info.out.size;
515 torture_comment(torture, "size: %u\n", (uint_t)correct_size);
517 SIZE_CHECK("GETATTR", getattr, size);
518 SIZE_CHECK("GETATTRE", getattre, size);
519 SIZE_CHECK("STANDARD", standard, size);
520 SIZE_CHECK("EA_SIZE", ea_size, size);
521 SIZE_CHECK("STANDARD_INFO", standard_info, size);
522 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
523 SIZE_CHECK("ALL_INFO", all_info, size);
524 SIZE_CHECK("ALL_INFORMATION", all_info, size);
525 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
526 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
527 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
529 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
530 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
534 s1 = fnum_find("STANDARD_INFO");
535 correct_size = s1->standard_info.out.alloc_size;
536 torture_comment(torture, "alloc_size: %u\n", (uint_t)correct_size);
538 SIZE_CHECK("GETATTRE", getattre, alloc_size);
539 SIZE_CHECK("STANDARD", standard, alloc_size);
540 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
541 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
542 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
543 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
544 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
545 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
547 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
548 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
551 #define ATTRIB_CHECK(sname, stype, tfield) do { \
552 s1 = fnum_find(sname); \
553 if (s1 && s1->stype.out.tfield != correct_attrib) { \
554 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
555 (uint_t)s1->stype.out.tfield, \
556 (uint_t)correct_attrib); \
559 s1 = fname_find(is_ipc, sname); \
560 if (s1 && s1->stype.out.tfield != correct_attrib) { \
561 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
562 (uint_t)s1->stype.out.tfield, \
563 (uint_t)correct_attrib); \
567 s1 = fnum_find("BASIC_INFO");
568 correct_attrib = s1->basic_info.out.attrib;
569 torture_comment(torture, "attrib: 0x%x\n", (uint_t)correct_attrib);
571 ATTRIB_CHECK("GETATTR", getattr, attrib);
573 ATTRIB_CHECK("GETATTRE", getattre, attrib);
574 ATTRIB_CHECK("STANDARD", standard, attrib);
575 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
577 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
578 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
579 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
580 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
581 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
582 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
584 correct_name = fname;
585 torture_comment(torture, "name: %s\n", correct_name);
587 #define NAME_CHECK(sname, stype, tfield, flags) do { \
588 s1 = fnum_find(sname); \
589 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
590 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
591 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
592 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
595 s1 = fname_find(is_ipc, sname); \
596 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
597 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
598 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
599 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
603 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
604 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
606 /* the ALL_INFO file name is the full path on the filesystem */
607 s1 = fnum_find("ALL_INFO");
608 if (s1 && !s1->all_info.out.fname.s) {
609 torture_fail(torture, "ALL_INFO didn't give a filename");
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 torture_comment(torture, "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 torture_comment(torture, "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 torture_comment(torture, "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 */
814 /* basic testing of all RAW_FILEINFO_* calls
815 for each call we test that it succeeds, and where possible test
816 for consistency between the calls.
818 bool torture_raw_qfileinfo(struct torture_context *torture,
819 struct smbcli_state *cli)
823 const char *fname = "\\torture_qfileinfo.txt";
825 fnum = create_complex_file(cli, torture, fname);
827 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
831 ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */);
833 smbcli_close(cli->tree, fnum);
834 smbcli_unlink(cli->tree, fname);
839 bool torture_raw_qfileinfo_pipe(struct torture_context *torture,
840 struct smbcli_state *cli)
844 const char *fname = "\\lsass";
845 struct dcerpc_pipe *p;
846 struct smbcli_tree *ipc_tree;
849 if (!(p = dcerpc_pipe_init(torture, cli->tree->session->transport->socket->event.ctx,
850 lp_iconv_convenience(torture->lp_ctx)))) {
854 status = dcerpc_pipe_open_smb(p, cli->tree, fname);
855 torture_assert_ntstatus_ok(torture, status, "dcerpc_pipe_open_smb failed");
857 ipc_tree = dcerpc_smb_tree(p->conn);
858 fnum = dcerpc_smb_fnum(p->conn);
860 ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, true /* is_ipc */);