2 Unix SMB/CIFS implementation.
3 RAW_FILEINFO_* individual test suite
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libcli/raw/libcliraw.h"
26 enum smb_fileinfo_level level;
28 uint_t only_handles:1;
29 uint32_t capability_mask;
30 NTSTATUS fnum_status, fname_status;
31 union smb_fileinfo fnum_finfo, fname_finfo;
33 { "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
34 { "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
35 { "STANDARD", RAW_FILEINFO_STANDARD, },
36 { "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
37 { "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
38 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
39 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
40 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
41 { "EA_INFO", RAW_FILEINFO_EA_INFO, },
42 { "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
43 { "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
44 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
45 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
46 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
47 { "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
48 { "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
49 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
50 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
51 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
52 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
53 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
54 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
55 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
56 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
57 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
58 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
59 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
60 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
61 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
62 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
63 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
68 compare a dos time (2 second resolution) to a nt time
70 static int dos_nt_time_cmp(time_t t, NTTIME nt)
72 time_t t2 = nt_time_to_unix(nt);
73 if (ABS(t2 - t) <= 2) return 0;
79 find a level in the levels[] table
81 static union smb_fileinfo *fnum_find(const char *name)
84 for (i=0; levels[i].name; i++) {
85 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
86 strcmp(name, levels[i].name) == 0 &&
87 !levels[i].only_paths) {
88 return &levels[i].fnum_finfo;
95 find a level in the levels[] table
97 static union smb_fileinfo *fname_find(const char *name)
100 for (i=0; levels[i].name; i++) {
101 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
102 strcmp(name, levels[i].name) == 0 &&
103 !levels[i].only_handles) {
104 return &levels[i].fname_finfo;
110 /* local macros to make the code below more readable */
111 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
112 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
113 #n1, #v1, (uint_t)s1->n1.out.v1, \
114 #n2, #v2, (uint_t)s2->n2.out.v2, \
115 __FILE__, __LINE__); \
119 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
120 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
121 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
122 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
123 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
124 __FILE__, __LINE__); \
128 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
129 printf("%s/%s != %s/%s at %s(%d)\n", \
132 __FILE__, __LINE__); \
136 /* used to find hints on unknown values - and to make sure
138 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
139 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
141 (uint_t)s1->n1.out.v1, \
142 (uint_t)s1->n1.out.v1, \
143 __FILE__, __LINE__); \
147 /* basic testing of all RAW_FILEINFO_* calls
148 for each call we test that it succeeds, and where possible test
149 for consistency between the calls.
151 BOOL torture_raw_qfileinfo(void)
153 struct smbcli_state *cli;
157 union smb_fileinfo *s1, *s2;
160 const char *fname = "\\torture_qfileinfo.txt";
162 uint64_t correct_size;
163 uint32_t correct_attrib;
164 const char *correct_name;
165 BOOL skip_streams = False;
167 if (!torture_open_connection(&cli)) {
171 mem_ctx = talloc_init("torture_qfileinfo");
173 fnum = create_complex_file(cli, mem_ctx, fname);
175 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
181 /* scan all the fileinfo and pathinfo levels */
182 for (i=0; levels[i].name; i++) {
183 if (!levels[i].only_paths) {
184 levels[i].fnum_finfo.generic.level = levels[i].level;
185 levels[i].fnum_finfo.generic.in.fnum = fnum;
186 levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
187 &levels[i].fnum_finfo);
190 if (!levels[i].only_handles) {
191 levels[i].fname_finfo.generic.level = levels[i].level;
192 levels[i].fname_finfo.generic.in.fname = talloc_strdup(mem_ctx, fname);
193 levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
194 &levels[i].fname_finfo);
198 /* check for completely broken levels */
199 for (count=i=0; levels[i].name; i++) {
200 uint32_t cap = cli->transport->negotiate.capabilities;
201 /* see if this server claims to support this level */
202 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
206 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
207 printf("ERROR: level %s failed - %s\n",
208 levels[i].name, nt_errstr(levels[i].fnum_status));
211 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
212 printf("ERROR: level %s failed - %s\n",
213 levels[i].name, nt_errstr(levels[i].fname_status));
220 printf("%d levels failed\n", count);
222 printf("too many level failures - giving up\n");
227 /* see if we can do streams */
228 s1 = fnum_find("STREAM_INFO");
229 if (!s1 || s1->stream_info.out.num_streams == 0) {
230 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
231 s1 ? s1->stream_info.out.num_streams : -1);
236 /* this code is incredibly repititive but doesn't lend itself to loops, so
237 we use lots of macros to make it less painful */
239 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
240 this code to fail, but we need to check it for completeness */
244 #define ALIAS_CHECK(sname1, sname2) \
246 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
247 if (s1 && s2) { INFO_CHECK } \
248 s1 = fname_find(sname1); s2 = fname_find(sname2); \
249 if (s1 && s2) { INFO_CHECK } \
250 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
251 if (s1 && s2) { INFO_CHECK } \
255 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
256 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
257 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
258 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
259 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
261 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
265 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
266 VAL_EQUAL(standard_info, size, standard_info, size); \
267 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
268 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
269 VAL_EQUAL(standard_info, directory, standard_info, directory);
271 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
275 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
277 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
281 STR_EQUAL(name_info, fname, name_info, fname);
283 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
287 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
288 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
289 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
290 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
291 VAL_EQUAL(all_info, attrib, all_info, attrib); \
292 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
293 VAL_EQUAL(all_info, size, all_info, size); \
294 VAL_EQUAL(all_info, nlink, all_info, nlink); \
295 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
296 VAL_EQUAL(all_info, directory, all_info, directory); \
297 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
298 STR_EQUAL(all_info, fname, all_info, fname);
300 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
304 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
305 VAL_EQUAL(compression_info, format, compression_info, format); \
306 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
307 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
308 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
310 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
315 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
317 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
320 #define TIME_CHECK_NT(sname, stype, tfield) do { \
321 s1 = fnum_find(sname); \
322 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
323 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
324 nt_time_string(mem_ctx, s1->stype.out.tfield), \
325 nt_time_string(mem_ctx, correct_time)); \
328 s1 = fname_find(sname); \
329 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
330 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
331 nt_time_string(mem_ctx, s1->stype.out.tfield), \
332 nt_time_string(mem_ctx, correct_time)); \
336 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
337 s1 = fnum_find(sname); \
338 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
339 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
340 timestring(mem_ctx, s1->stype.out.tfield), \
341 nt_time_string(mem_ctx, correct_time)); \
344 s1 = fname_find(sname); \
345 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
346 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
347 timestring(mem_ctx, s1->stype.out.tfield), \
348 nt_time_string(mem_ctx, correct_time)); \
352 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
353 s1 = fnum_find(sname); \
354 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
355 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
356 timestring(mem_ctx, s1->stype.out.tfield), \
357 nt_time_string(mem_ctx, correct_time)); \
360 s1 = fname_find(sname); \
361 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
362 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
363 timestring(mem_ctx, s1->stype.out.tfield), \
364 nt_time_string(mem_ctx, correct_time)); \
368 /* now check that all the times that are supposed to be equal are correct */
369 s1 = fnum_find("BASIC_INFO");
370 correct_time = s1->basic_info.out.create_time;
371 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
373 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
374 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
375 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
376 TIME_CHECK_DOS("STANDARD", standard, create_time);
377 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
378 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
379 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
381 s1 = fnum_find("BASIC_INFO");
382 correct_time = s1->basic_info.out.access_time;
383 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
385 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
386 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
387 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
388 TIME_CHECK_DOS("STANDARD", standard, access_time);
389 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
390 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
391 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
393 s1 = fnum_find("BASIC_INFO");
394 correct_time = s1->basic_info.out.write_time;
395 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
397 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
398 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
399 TIME_CHECK_DOS("GETATTR", getattr, write_time);
400 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
401 TIME_CHECK_DOS("STANDARD", standard, write_time);
402 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
403 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
404 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
406 s1 = fnum_find("BASIC_INFO");
407 correct_time = s1->basic_info.out.change_time;
408 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
410 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
411 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
412 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
413 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
416 #define SIZE_CHECK(sname, stype, tfield) do { \
417 s1 = fnum_find(sname); \
418 if (s1 && s1->stype.out.tfield != correct_size) { \
419 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
420 (uint_t)s1->stype.out.tfield, \
421 (uint_t)correct_size); \
424 s1 = fname_find(sname); \
425 if (s1 && s1->stype.out.tfield != correct_size) { \
426 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
427 (uint_t)s1->stype.out.tfield, \
428 (uint_t)correct_size); \
432 s1 = fnum_find("STANDARD_INFO");
433 correct_size = s1->standard_info.out.size;
434 printf("size: %u\n", (uint_t)correct_size);
436 SIZE_CHECK("GETATTR", getattr, size);
437 SIZE_CHECK("GETATTRE", getattre, size);
438 SIZE_CHECK("STANDARD", standard, size);
439 SIZE_CHECK("EA_SIZE", ea_size, size);
440 SIZE_CHECK("STANDARD_INFO", standard_info, size);
441 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
442 SIZE_CHECK("ALL_INFO", all_info, size);
443 SIZE_CHECK("ALL_INFORMATION", all_info, size);
444 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
445 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
446 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
448 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
449 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
453 s1 = fnum_find("STANDARD_INFO");
454 correct_size = s1->standard_info.out.alloc_size;
455 printf("alloc_size: %u\n", (uint_t)correct_size);
457 SIZE_CHECK("GETATTRE", getattre, alloc_size);
458 SIZE_CHECK("STANDARD", standard, alloc_size);
459 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
460 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
461 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
462 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
463 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
464 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
466 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
467 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
470 #define ATTRIB_CHECK(sname, stype, tfield) do { \
471 s1 = fnum_find(sname); \
472 if (s1 && s1->stype.out.tfield != correct_attrib) { \
473 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
474 (uint_t)s1->stype.out.tfield, \
475 (uint_t)correct_attrib); \
478 s1 = fname_find(sname); \
479 if (s1 && s1->stype.out.tfield != correct_attrib) { \
480 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
481 (uint_t)s1->stype.out.tfield, \
482 (uint_t)correct_attrib); \
486 s1 = fnum_find("BASIC_INFO");
487 correct_attrib = s1->basic_info.out.attrib;
488 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
490 ATTRIB_CHECK("GETATTR", getattr, attrib);
491 ATTRIB_CHECK("GETATTRE", getattre, attrib);
492 ATTRIB_CHECK("STANDARD", standard, attrib);
493 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
494 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
495 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
496 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
497 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
498 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
499 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
501 correct_name = fname;
502 printf("name: %s\n", correct_name);
504 #define NAME_CHECK(sname, stype, tfield, flags) do { \
505 s1 = fnum_find(sname); \
506 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
507 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
508 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
509 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
512 s1 = fname_find(sname); \
513 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
514 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
515 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
516 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
520 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
521 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
523 /* the ALL_INFO file name is the full path on the filesystem */
524 s1 = fnum_find("ALL_INFO");
525 if (s1 && !s1->all_info.out.fname.s) {
526 printf("ALL_INFO didn't give a filename\n");
529 if (s1 && s1->all_info.out.fname.s) {
530 char *p = strrchr(s1->all_info.out.fname.s, '\\');
532 printf("Not a full path in all_info/fname? - '%s'\n",
533 s1->all_info.out.fname.s);
536 if (strcmp_safe(correct_name, p) != 0) {
537 printf("incorrect basename in all_info/fname - '%s'\n",
538 s1->all_info.out.fname.s);
542 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, cli)) {
543 printf("Should not null terminate all_info/fname\n");
548 s1 = fnum_find("ALT_NAME_INFO");
549 correct_name = s1->alt_name_info.out.fname.s;
550 printf("alt_name: %s\n", correct_name);
552 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
553 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
555 /* and make sure we can open by alternate name */
556 smbcli_close(cli->tree, fnum);
557 fnum = smbcli_nt_create_full(cli->tree, correct_name, 0,
559 FILE_ATTRIBUTE_NORMAL,
560 NTCREATEX_SHARE_ACCESS_DELETE|
561 NTCREATEX_SHARE_ACCESS_READ|
562 NTCREATEX_SHARE_ACCESS_WRITE,
563 NTCREATEX_DISP_OVERWRITE_IF,
566 printf("Unable to open by alt_name - %s\n", smbcli_errstr(cli->tree));
571 correct_name = "::$DATA";
572 printf("stream_name: %s\n", correct_name);
574 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
575 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
578 /* make sure the EAs look right */
579 s1 = fnum_find("ALL_EAS");
580 s2 = fnum_find("ALL_INFO");
582 for (i=0;i<s1->all_eas.out.num_eas;i++) {
583 printf(" flags=%d %s=%*.*s\n",
584 s1->all_eas.out.eas[i].flags,
585 s1->all_eas.out.eas[i].name.s,
586 (int)s1->all_eas.out.eas[i].value.length,
587 (int)s1->all_eas.out.eas[i].value.length,
588 s1->all_eas.out.eas[i].value.data);
592 if (s1->all_eas.out.num_eas == 0) {
593 if (s2->all_info.out.ea_size != 0) {
594 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
595 s2->all_info.out.ea_size);
598 if (s2->all_info.out.ea_size !=
599 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
600 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
601 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
602 s2->all_info.out.ea_size);
606 s2 = fname_find("ALL_EAS");
608 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
609 for (i=0;i<s1->all_eas.out.num_eas;i++) {
610 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
611 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
612 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
616 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
617 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
618 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
619 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
620 #stype1, #tfield1, #stype2, #tfield2, \
621 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
624 s1 = fname_find(sname1); s2 = fname_find(sname2); \
625 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
626 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
627 #stype1, #tfield1, #stype2, #tfield2, \
628 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
631 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
632 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
633 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
634 #stype1, #tfield1, #stype2, #tfield2, \
635 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
638 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
639 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
640 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
641 #stype1, #tfield1, #stype2, #tfield2, \
642 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
646 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
647 "ALL_INFO", all_info, delete_pending);
648 VAL_CHECK("STANDARD_INFO", standard_info, directory,
649 "ALL_INFO", all_info, directory);
650 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
651 "ALL_INFO", all_info, nlink);
652 VAL_CHECK("EA_INFO", ea_info, ea_size,
653 "ALL_INFO", all_info, ea_size);
654 VAL_CHECK("EA_SIZE", ea_size, ea_size,
655 "ALL_INFO", all_info, ea_size);
658 #define NAME_PATH_CHECK(sname, stype, field) do { \
659 s1 = fname_find(sname); s2 = fnum_find(sname); \
661 VAL_EQUAL(stype, field, stype, field); \
666 s1 = fnum_find("INTERNAL_INFORMATION");
668 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
671 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
672 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
674 printf("fnum pos = %.0f, fname pos = %.0f\n",
675 (double)s2->position_information.out.position,
676 (double)s1->position_information.out.position );
678 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
679 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
680 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
681 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
684 /* these are expected to differ */
685 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
688 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
689 s1 = fnum_find(sname); \
690 if (s1 && s1->stype.out.tfield != 0) { \
691 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
693 (uint_t)s1->stype.out.tfield); \
695 s1 = fname_find(sname); \
696 if (s1 && s1->stype.out.tfield != 0) { \
697 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
699 (uint_t)s1->stype.out.tfield); \
702 /* now get a bit fancier .... */
704 /* when we set the delete disposition then the link count should drop
705 to 0 and delete_pending should be 1 */
709 smbcli_close(cli->tree, fnum);
710 smbcli_unlink(cli->tree, fname);
712 torture_close_connection(cli);
713 talloc_free(mem_ctx);