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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "torture/torture.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "torture/rpc/rpc.h"
32 enum smb_fileinfo_level level;
34 uint_t only_handles:1;
35 uint32_t capability_mask;
36 uint_t expected_ipc_access_denied:1;
37 NTSTATUS expected_ipc_fnum_status;
38 NTSTATUS fnum_status, fname_status;
39 union smb_fileinfo fnum_finfo, fname_finfo;
42 .level = RAW_FILEINFO_GETATTR,
45 .expected_ipc_access_denied = 1},
47 .level = RAW_FILEINFO_GETATTRE,
51 .level = RAW_FILEINFO_STANDARD, },
53 .level = RAW_FILEINFO_EA_SIZE },
55 .level = RAW_FILEINFO_ALL_EAS,
56 .expected_ipc_fnum_status = NT_STATUS_ACCESS_DENIED,
58 { .name ="IS_NAME_VALID",
59 .level = RAW_FILEINFO_IS_NAME_VALID,
62 { .name ="BASIC_INFO",
63 .level = RAW_FILEINFO_BASIC_INFO },
64 { .name ="STANDARD_INFO",
65 .level = RAW_FILEINFO_STANDARD_INFO },
67 .level = RAW_FILEINFO_EA_INFO },
69 .level = RAW_FILEINFO_NAME_INFO },
71 .level = RAW_FILEINFO_ALL_INFO },
72 { .name ="ALT_NAME_INFO",
73 .level = RAW_FILEINFO_ALT_NAME_INFO,
74 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
76 { .name ="STREAM_INFO",
77 .level = RAW_FILEINFO_STREAM_INFO,
78 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
80 { .name ="COMPRESSION_INFO",
81 .level = RAW_FILEINFO_COMPRESSION_INFO,
82 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
84 { .name ="UNIX_BASIC_INFO",
85 .level = RAW_FILEINFO_UNIX_BASIC,
88 .capability_mask = CAP_UNIX},
89 { .name ="UNIX_LINK_INFO",
90 .level = RAW_FILEINFO_UNIX_LINK,
93 .capability_mask = CAP_UNIX},
94 { .name ="BASIC_INFORMATION",
95 .level = RAW_FILEINFO_BASIC_INFORMATION },
96 { .name ="STANDARD_INFORMATION",
97 .level = RAW_FILEINFO_STANDARD_INFORMATION },
98 { .name ="INTERNAL_INFORMATION",
99 .level = RAW_FILEINFO_INTERNAL_INFORMATION },
100 { .name ="EA_INFORMATION",
101 .level = RAW_FILEINFO_EA_INFORMATION },
102 { .name = "ACCESS_INFORMATION",
103 .level = RAW_FILEINFO_ACCESS_INFORMATION },
104 { .name = "NAME_INFORMATION",
105 .level = RAW_FILEINFO_NAME_INFORMATION },
106 { .name ="POSITION_INFORMATION",
107 .level = RAW_FILEINFO_POSITION_INFORMATION },
108 { .name ="MODE_INFORMATION",
109 .level = RAW_FILEINFO_MODE_INFORMATION },
110 { .name ="ALIGNMENT_INFORMATION",
111 .level = RAW_FILEINFO_ALIGNMENT_INFORMATION },
112 { .name ="ALL_INFORMATION",
113 .level = RAW_FILEINFO_ALL_INFORMATION },
114 { .name ="ALT_NAME_INFORMATION",
115 .level = RAW_FILEINFO_ALT_NAME_INFORMATION,
116 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
118 { .name ="STREAM_INFORMATION",
119 .level = RAW_FILEINFO_STREAM_INFORMATION,
120 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
122 { .name = "COMPRESSION_INFORMATION",
123 .level = RAW_FILEINFO_COMPRESSION_INFORMATION,
124 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
126 { .name ="NETWORK_OPEN_INFORMATION",
127 .level = RAW_FILEINFO_NETWORK_OPEN_INFORMATION,
128 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
130 { .name = "ATTRIBUTE_TAG_INFORMATION",
131 .level = RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION,
132 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
138 compare a dos time (2 second resolution) to a nt time
140 static int dos_nt_time_cmp(time_t t, NTTIME nt)
142 time_t t2 = nt_time_to_unix(nt);
143 if (abs(t2 - t) <= 2) return 0;
149 find a level in the levels[] table
151 static union smb_fileinfo *fnum_find(const char *name)
154 for (i=0; levels[i].name; i++) {
155 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
156 strcmp(name, levels[i].name) == 0 &&
157 !levels[i].only_paths) {
158 return &levels[i].fnum_finfo;
165 find a level in the levels[] table
167 static union smb_fileinfo *fname_find(bool is_ipc, const char *name)
173 for (i=0; levels[i].name; i++) {
174 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
175 strcmp(name, levels[i].name) == 0 &&
176 !levels[i].only_handles) {
177 return &levels[i].fname_finfo;
183 /* local macros to make the code below more readable */
184 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
185 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
186 #n1, #v1, (uint_t)s1->n1.out.v1, \
187 #n2, #v2, (uint_t)s2->n2.out.v2, \
188 __FILE__, __LINE__); \
192 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
193 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
194 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
195 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
196 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
197 __FILE__, __LINE__); \
201 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
202 printf("%s/%s != %s/%s at %s(%d)\n", \
205 __FILE__, __LINE__); \
209 /* used to find hints on unknown values - and to make sure
212 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
213 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
215 (uint_t)s1->n1.out.v1, \
216 (uint_t)s1->n1.out.v1, \
217 __FILE__, __LINE__); \
222 /* basic testing of all RAW_FILEINFO_* calls
223 for each call we test that it succeeds, and where possible test
224 for consistency between the calls.
226 static BOOL torture_raw_qfileinfo_internals(struct torture_context *torture, TALLOC_CTX *mem_ctx,
227 struct smbcli_tree *tree, int fnum, const char *fname,
233 union smb_fileinfo *s1, *s2;
235 uint64_t correct_size;
236 uint32_t correct_attrib;
237 const char *correct_name;
238 BOOL skip_streams = False;
240 /* scan all the fileinfo and pathinfo levels */
241 for (i=0; levels[i].name; i++) {
242 if (!levels[i].only_paths) {
243 levels[i].fnum_finfo.generic.level = levels[i].level;
244 levels[i].fnum_finfo.generic.in.file.fnum = fnum;
245 levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx,
246 &levels[i].fnum_finfo);
249 if (!levels[i].only_handles) {
250 levels[i].fname_finfo.generic.level = levels[i].level;
251 levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
252 levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx,
253 &levels[i].fname_finfo);
257 /* check for completely broken levels */
258 for (count=i=0; levels[i].name; i++) {
259 uint32_t cap = tree->session->transport->negotiate.capabilities;
260 /* see if this server claims to support this level */
261 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
266 if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
267 } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
268 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n",
269 levels[i].name, nt_errstr(levels[i].fname_status));
272 if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
273 printf("ERROR: fnum level %s failed, expected %s - %s\n",
274 levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status),
275 nt_errstr(levels[i].fnum_status));
279 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
280 printf("ERROR: fnum level %s failed - %s\n",
281 levels[i].name, nt_errstr(levels[i].fnum_status));
284 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
285 printf("ERROR: fname level %s failed - %s\n",
286 levels[i].name, nt_errstr(levels[i].fname_status));
295 printf("%d levels failed\n", count);
297 printf("too many level failures - giving up\n");
302 /* see if we can do streams */
303 s1 = fnum_find("STREAM_INFO");
304 if (!s1 || s1->stream_info.out.num_streams == 0) {
306 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
307 s1 ? s1->stream_info.out.num_streams : -1);
313 /* this code is incredibly repititive but doesn't lend itself to loops, so
314 we use lots of macros to make it less painful */
316 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
317 this code to fail, but we need to check it for completeness */
321 #define ALIAS_CHECK(sname1, sname2) \
323 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
324 if (s1 && s2) { INFO_CHECK } \
325 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
326 if (s1 && s2) { INFO_CHECK } \
327 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
328 if (s1 && s2) { INFO_CHECK } \
332 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
333 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
334 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
335 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
336 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
338 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
342 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
343 VAL_EQUAL(standard_info, size, standard_info, size); \
344 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
345 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
346 VAL_EQUAL(standard_info, directory, standard_info, directory);
348 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
352 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
354 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
358 STR_EQUAL(name_info, fname, name_info, fname);
360 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
364 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
365 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
366 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
367 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
368 VAL_EQUAL(all_info, attrib, all_info, attrib); \
369 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
370 VAL_EQUAL(all_info, size, all_info, size); \
371 VAL_EQUAL(all_info, nlink, all_info, nlink); \
372 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
373 VAL_EQUAL(all_info, directory, all_info, directory); \
374 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
375 STR_EQUAL(all_info, fname, all_info, fname);
377 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
381 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
382 VAL_EQUAL(compression_info, format, compression_info, format); \
383 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
384 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
385 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
387 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
392 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
394 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
397 #define TIME_CHECK_NT(sname, stype, tfield) do { \
398 s1 = fnum_find(sname); \
399 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
400 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
401 nt_time_string(mem_ctx, s1->stype.out.tfield), \
402 nt_time_string(mem_ctx, correct_time)); \
405 s1 = fname_find(is_ipc, sname); \
406 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
407 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
408 nt_time_string(mem_ctx, s1->stype.out.tfield), \
409 nt_time_string(mem_ctx, correct_time)); \
413 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
414 s1 = fnum_find(sname); \
415 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
416 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
417 timestring(mem_ctx, s1->stype.out.tfield), \
418 nt_time_string(mem_ctx, correct_time)); \
421 s1 = fname_find(is_ipc, sname); \
422 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
423 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
424 timestring(mem_ctx, s1->stype.out.tfield), \
425 nt_time_string(mem_ctx, correct_time)); \
430 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
431 s1 = fnum_find(sname); \
432 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
433 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
434 timestring(mem_ctx, s1->stype.out.tfield), \
435 nt_time_string(mem_ctx, correct_time)); \
438 s1 = fname_find(is_ipc, sname); \
439 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
440 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
441 timestring(mem_ctx, s1->stype.out.tfield), \
442 nt_time_string(mem_ctx, correct_time)); \
447 /* now check that all the times that are supposed to be equal are correct */
448 s1 = fnum_find("BASIC_INFO");
449 correct_time = s1->basic_info.out.create_time;
450 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
452 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
453 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
454 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
455 TIME_CHECK_DOS("STANDARD", standard, create_time);
456 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
457 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
458 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
460 s1 = fnum_find("BASIC_INFO");
461 correct_time = s1->basic_info.out.access_time;
462 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
464 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
465 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
466 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
467 TIME_CHECK_DOS("STANDARD", standard, access_time);
468 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
469 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
470 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
472 s1 = fnum_find("BASIC_INFO");
473 correct_time = s1->basic_info.out.write_time;
474 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
476 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
477 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
478 TIME_CHECK_DOS("GETATTR", getattr, write_time);
479 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
480 TIME_CHECK_DOS("STANDARD", standard, write_time);
481 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
482 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
483 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
485 s1 = fnum_find("BASIC_INFO");
486 correct_time = s1->basic_info.out.change_time;
487 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
489 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
490 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
491 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
492 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
495 #define SIZE_CHECK(sname, stype, tfield) do { \
496 s1 = fnum_find(sname); \
497 if (s1 && s1->stype.out.tfield != correct_size) { \
498 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
499 (uint_t)s1->stype.out.tfield, \
500 (uint_t)correct_size); \
503 s1 = fname_find(is_ipc, sname); \
504 if (s1 && s1->stype.out.tfield != correct_size) { \
505 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
506 (uint_t)s1->stype.out.tfield, \
507 (uint_t)correct_size); \
511 s1 = fnum_find("STANDARD_INFO");
512 correct_size = s1->standard_info.out.size;
513 printf("size: %u\n", (uint_t)correct_size);
515 SIZE_CHECK("GETATTR", getattr, size);
516 SIZE_CHECK("GETATTRE", getattre, size);
517 SIZE_CHECK("STANDARD", standard, size);
518 SIZE_CHECK("EA_SIZE", ea_size, size);
519 SIZE_CHECK("STANDARD_INFO", standard_info, size);
520 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
521 SIZE_CHECK("ALL_INFO", all_info, size);
522 SIZE_CHECK("ALL_INFORMATION", all_info, size);
523 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
524 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
525 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
527 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
528 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
532 s1 = fnum_find("STANDARD_INFO");
533 correct_size = s1->standard_info.out.alloc_size;
534 printf("alloc_size: %u\n", (uint_t)correct_size);
536 SIZE_CHECK("GETATTRE", getattre, alloc_size);
537 SIZE_CHECK("STANDARD", standard, alloc_size);
538 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
539 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
540 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
541 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
542 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
543 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
545 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
546 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
549 #define ATTRIB_CHECK(sname, stype, tfield) do { \
550 s1 = fnum_find(sname); \
551 if (s1 && s1->stype.out.tfield != correct_attrib) { \
552 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
553 (uint_t)s1->stype.out.tfield, \
554 (uint_t)correct_attrib); \
557 s1 = fname_find(is_ipc, sname); \
558 if (s1 && s1->stype.out.tfield != correct_attrib) { \
559 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
560 (uint_t)s1->stype.out.tfield, \
561 (uint_t)correct_attrib); \
565 s1 = fnum_find("BASIC_INFO");
566 correct_attrib = s1->basic_info.out.attrib;
567 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
569 ATTRIB_CHECK("GETATTR", getattr, attrib);
571 ATTRIB_CHECK("GETATTRE", getattre, attrib);
572 ATTRIB_CHECK("STANDARD", standard, attrib);
573 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
575 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
576 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
577 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
578 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
579 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
580 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
582 correct_name = fname;
583 printf("name: %s\n", correct_name);
585 #define NAME_CHECK(sname, stype, tfield, flags) do { \
586 s1 = fnum_find(sname); \
587 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
588 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
589 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
590 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
593 s1 = fname_find(is_ipc, sname); \
594 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
595 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
596 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
597 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
601 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
602 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
604 /* the ALL_INFO file name is the full path on the filesystem */
605 s1 = fnum_find("ALL_INFO");
606 if (s1 && !s1->all_info.out.fname.s) {
607 printf("ALL_INFO didn't give a filename\n");
610 if (s1 && s1->all_info.out.fname.s) {
611 char *p = strrchr(s1->all_info.out.fname.s, '\\');
613 printf("Not a full path in all_info/fname? - '%s'\n",
614 s1->all_info.out.fname.s);
617 if (strcmp_safe(correct_name, p) != 0) {
618 printf("incorrect basename in all_info/fname - '%s'\n",
619 s1->all_info.out.fname.s);
623 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
624 printf("Should not null terminate all_info/fname\n");
629 s1 = fnum_find("ALT_NAME_INFO");
631 correct_name = s1->alt_name_info.out.fname.s;
632 printf("alt_name: %s\n", correct_name);
634 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
635 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
637 /* and make sure we can open by alternate name */
638 smbcli_close(tree, fnum);
639 fnum = smbcli_nt_create_full(tree, correct_name, 0,
641 FILE_ATTRIBUTE_NORMAL,
642 NTCREATEX_SHARE_ACCESS_DELETE|
643 NTCREATEX_SHARE_ACCESS_READ|
644 NTCREATEX_SHARE_ACCESS_WRITE,
645 NTCREATEX_DISP_OVERWRITE_IF,
648 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
653 correct_name = "::$DATA";
654 printf("stream_name: %s\n", correct_name);
656 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
657 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
661 /* make sure the EAs look right */
662 s1 = fnum_find("ALL_EAS");
663 s2 = fnum_find("ALL_INFO");
665 for (i=0;i<s1->all_eas.out.num_eas;i++) {
666 printf(" flags=%d %s=%*.*s\n",
667 s1->all_eas.out.eas[i].flags,
668 s1->all_eas.out.eas[i].name.s,
669 (int)s1->all_eas.out.eas[i].value.length,
670 (int)s1->all_eas.out.eas[i].value.length,
671 s1->all_eas.out.eas[i].value.data);
675 if (s1->all_eas.out.num_eas == 0) {
676 if (s2->all_info.out.ea_size != 0) {
677 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
678 s2->all_info.out.ea_size);
681 if (s2->all_info.out.ea_size !=
682 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
683 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
684 (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
685 (int)s2->all_info.out.ea_size);
689 s2 = fname_find(is_ipc, "ALL_EAS");
691 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
692 for (i=0;i<s1->all_eas.out.num_eas;i++) {
693 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
694 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
695 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
699 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
700 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
701 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
702 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
703 #stype1, #tfield1, #stype2, #tfield2, \
704 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
707 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
708 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
709 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
710 #stype1, #tfield1, #stype2, #tfield2, \
711 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
714 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
715 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
716 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
717 #stype1, #tfield1, #stype2, #tfield2, \
718 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
721 s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
722 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
723 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
724 #stype1, #tfield1, #stype2, #tfield2, \
725 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
729 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
730 "ALL_INFO", all_info, delete_pending);
731 VAL_CHECK("STANDARD_INFO", standard_info, directory,
732 "ALL_INFO", all_info, directory);
733 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
734 "ALL_INFO", all_info, nlink);
735 s1 = fnum_find("BASIC_INFO");
737 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
738 printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
742 s1 = fnum_find("STANDARD_INFO");
744 if (s1->standard_info.out.nlink != 1) {
745 printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
748 if (s1->standard_info.out.delete_pending != 1) {
749 printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
753 VAL_CHECK("EA_INFO", ea_info, ea_size,
754 "ALL_INFO", all_info, ea_size);
756 VAL_CHECK("EA_SIZE", ea_size, ea_size,
757 "ALL_INFO", all_info, ea_size);
760 #define NAME_PATH_CHECK(sname, stype, field) do { \
761 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
763 VAL_EQUAL(stype, field, stype, field); \
768 s1 = fnum_find("INTERNAL_INFORMATION");
770 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
773 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
774 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
776 printf("fnum pos = %.0f, fname pos = %.0f\n",
777 (double)s2->position_information.out.position,
778 (double)s1->position_information.out.position );
780 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
781 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
782 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
783 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
786 /* these are expected to differ */
787 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
791 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
792 s1 = fnum_find(sname); \
793 if (s1 && s1->stype.out.tfield != 0) { \
794 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
796 (uint_t)s1->stype.out.tfield); \
798 s1 = fname_find(is_ipc, sname); \
799 if (s1 && s1->stype.out.tfield != 0) { \
800 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
802 (uint_t)s1->stype.out.tfield); \
805 /* now get a bit fancier .... */
807 /* when we set the delete disposition then the link count should drop
808 to 0 and delete_pending should be 1 */
816 /* basic testing of all RAW_FILEINFO_* calls
817 for each call we test that it succeeds, and where possible test
818 for consistency between the calls.
820 BOOL torture_raw_qfileinfo(struct torture_context *torture)
822 struct smbcli_state *cli;
826 const char *fname = "\\torture_qfileinfo.txt";
828 if (!torture_open_connection(&cli, 0)) {
832 mem_ctx = talloc_init("torture_qfileinfo");
834 fnum = create_complex_file(cli, mem_ctx, fname);
836 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
841 ret = torture_raw_qfileinfo_internals(torture, mem_ctx, cli->tree, fnum, fname, False /* is_ipc */);
843 smbcli_close(cli->tree, fnum);
844 smbcli_unlink(cli->tree, fname);
847 torture_close_connection(cli);
848 talloc_free(mem_ctx);
852 BOOL torture_raw_qfileinfo_pipe(struct torture_context *torture)
857 const char *fname = "\\lsass";
858 struct smbcli_state *cli;
859 struct dcerpc_pipe *p;
860 struct smbcli_tree *ipc_tree;
863 if (!torture_open_connection(&cli, 0)) {
867 mem_ctx = talloc_init("torture_qfileinfo_pipe");
869 if (!(p = dcerpc_pipe_init(mem_ctx,
870 cli->tree->session->transport->socket->event.ctx))) {
874 status = dcerpc_pipe_open_smb(p, cli->tree, fname);
875 if (!NT_STATUS_IS_OK(status)) {
876 d_printf("dcerpc_pipe_open_smb failed: %s\n",
882 ipc_tree = dcerpc_smb_tree(p->conn);
883 fnum = dcerpc_smb_fnum(p->conn);
885 ret = torture_raw_qfileinfo_internals(torture, mem_ctx, ipc_tree, fnum, fname, True /* is_ipc */);