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 "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
27 enum smb_fileinfo_level level;
29 uint_t only_handles:1;
30 uint32_t capability_mask;
31 NTSTATUS fnum_status, fname_status;
32 union smb_fileinfo fnum_finfo, fname_finfo;
34 { "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
35 { "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
36 { "STANDARD", RAW_FILEINFO_STANDARD, },
37 { "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
38 { "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
39 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
40 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
41 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
42 { "EA_INFO", RAW_FILEINFO_EA_INFO, },
43 { "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
44 { "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
45 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
46 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
47 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
48 { "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
49 { "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
50 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
51 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
52 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
53 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
54 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
55 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
56 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
57 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
58 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
59 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
60 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
61 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
62 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
63 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
64 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
69 compare a dos time (2 second resolution) to a nt time
71 static int dos_nt_time_cmp(time_t t, NTTIME nt)
73 time_t t2 = nt_time_to_unix(nt);
74 if (ABS(t2 - t) <= 2) return 0;
80 find a level in the levels[] table
82 static union smb_fileinfo *fnum_find(const char *name)
85 for (i=0; levels[i].name; i++) {
86 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
87 strcmp(name, levels[i].name) == 0 &&
88 !levels[i].only_paths) {
89 return &levels[i].fnum_finfo;
96 find a level in the levels[] table
98 static union smb_fileinfo *fname_find(const char *name)
101 for (i=0; levels[i].name; i++) {
102 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
103 strcmp(name, levels[i].name) == 0 &&
104 !levels[i].only_handles) {
105 return &levels[i].fname_finfo;
111 /* local macros to make the code below more readable */
112 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
113 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
114 #n1, #v1, (uint_t)s1->n1.out.v1, \
115 #n2, #v2, (uint_t)s2->n2.out.v2, \
116 __FILE__, __LINE__); \
120 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
121 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
122 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
123 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
124 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
125 __FILE__, __LINE__); \
129 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
130 printf("%s/%s != %s/%s at %s(%d)\n", \
133 __FILE__, __LINE__); \
137 /* used to find hints on unknown values - and to make sure
139 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
140 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
142 (uint_t)s1->n1.out.v1, \
143 (uint_t)s1->n1.out.v1, \
144 __FILE__, __LINE__); \
148 /* basic testing of all RAW_FILEINFO_* calls
149 for each call we test that it succeeds, and where possible test
150 for consistency between the calls.
152 BOOL torture_raw_qfileinfo(void)
154 struct smbcli_state *cli;
158 union smb_fileinfo *s1, *s2;
161 const char *fname = "\\torture_qfileinfo.txt";
163 uint64_t correct_size;
164 uint32_t correct_attrib;
165 const char *correct_name;
166 BOOL skip_streams = False;
168 if (!torture_open_connection(&cli)) {
172 mem_ctx = talloc_init("torture_qfileinfo");
174 fnum = create_complex_file(cli, mem_ctx, fname);
176 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
182 /* scan all the fileinfo and pathinfo levels */
183 for (i=0; levels[i].name; i++) {
184 if (!levels[i].only_paths) {
185 levels[i].fnum_finfo.generic.level = levels[i].level;
186 levels[i].fnum_finfo.generic.in.fnum = fnum;
187 levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
188 &levels[i].fnum_finfo);
191 if (!levels[i].only_handles) {
192 levels[i].fname_finfo.generic.level = levels[i].level;
193 levels[i].fname_finfo.generic.in.fname = talloc_strdup(mem_ctx, fname);
194 levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
195 &levels[i].fname_finfo);
199 /* check for completely broken levels */
200 for (count=i=0; levels[i].name; i++) {
201 uint32_t cap = cli->transport->negotiate.capabilities;
202 /* see if this server claims to support this level */
203 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
207 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
208 printf("ERROR: level %s failed - %s\n",
209 levels[i].name, nt_errstr(levels[i].fnum_status));
212 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
213 printf("ERROR: level %s failed - %s\n",
214 levels[i].name, nt_errstr(levels[i].fname_status));
221 printf("%d levels failed\n", count);
223 printf("too many level failures - giving up\n");
228 /* see if we can do streams */
229 s1 = fnum_find("STREAM_INFO");
230 if (!s1 || s1->stream_info.out.num_streams == 0) {
231 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
232 s1 ? s1->stream_info.out.num_streams : -1);
237 /* this code is incredibly repititive but doesn't lend itself to loops, so
238 we use lots of macros to make it less painful */
240 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
241 this code to fail, but we need to check it for completeness */
245 #define ALIAS_CHECK(sname1, sname2) \
247 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
248 if (s1 && s2) { INFO_CHECK } \
249 s1 = fname_find(sname1); s2 = fname_find(sname2); \
250 if (s1 && s2) { INFO_CHECK } \
251 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
252 if (s1 && s2) { INFO_CHECK } \
256 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
257 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
258 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
259 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
260 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
262 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
266 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
267 VAL_EQUAL(standard_info, size, standard_info, size); \
268 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
269 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
270 VAL_EQUAL(standard_info, directory, standard_info, directory);
272 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
276 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
278 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
282 STR_EQUAL(name_info, fname, name_info, fname);
284 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
288 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
289 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
290 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
291 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
292 VAL_EQUAL(all_info, attrib, all_info, attrib); \
293 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
294 VAL_EQUAL(all_info, size, all_info, size); \
295 VAL_EQUAL(all_info, nlink, all_info, nlink); \
296 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
297 VAL_EQUAL(all_info, directory, all_info, directory); \
298 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
299 STR_EQUAL(all_info, fname, all_info, fname);
301 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
305 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
306 VAL_EQUAL(compression_info, format, compression_info, format); \
307 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
308 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
309 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
311 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
316 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
318 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
321 #define TIME_CHECK_NT(sname, stype, tfield) do { \
322 s1 = fnum_find(sname); \
323 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
324 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
325 nt_time_string(mem_ctx, s1->stype.out.tfield), \
326 nt_time_string(mem_ctx, correct_time)); \
329 s1 = fname_find(sname); \
330 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
331 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
332 nt_time_string(mem_ctx, s1->stype.out.tfield), \
333 nt_time_string(mem_ctx, correct_time)); \
337 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
338 s1 = fnum_find(sname); \
339 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
340 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
341 timestring(mem_ctx, s1->stype.out.tfield), \
342 nt_time_string(mem_ctx, correct_time)); \
345 s1 = fname_find(sname); \
346 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
347 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
348 timestring(mem_ctx, s1->stype.out.tfield), \
349 nt_time_string(mem_ctx, correct_time)); \
353 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
354 s1 = fnum_find(sname); \
355 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
356 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
357 timestring(mem_ctx, s1->stype.out.tfield), \
358 nt_time_string(mem_ctx, correct_time)); \
361 s1 = fname_find(sname); \
362 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
363 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
364 timestring(mem_ctx, s1->stype.out.tfield), \
365 nt_time_string(mem_ctx, correct_time)); \
369 /* now check that all the times that are supposed to be equal are correct */
370 s1 = fnum_find("BASIC_INFO");
371 correct_time = s1->basic_info.out.create_time;
372 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
374 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
375 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
376 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
377 TIME_CHECK_DOS("STANDARD", standard, create_time);
378 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
379 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
380 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
382 s1 = fnum_find("BASIC_INFO");
383 correct_time = s1->basic_info.out.access_time;
384 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
386 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
387 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
388 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
389 TIME_CHECK_DOS("STANDARD", standard, access_time);
390 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
391 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
392 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
394 s1 = fnum_find("BASIC_INFO");
395 correct_time = s1->basic_info.out.write_time;
396 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
398 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
399 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
400 TIME_CHECK_DOS("GETATTR", getattr, write_time);
401 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
402 TIME_CHECK_DOS("STANDARD", standard, write_time);
403 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
404 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
405 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
407 s1 = fnum_find("BASIC_INFO");
408 correct_time = s1->basic_info.out.change_time;
409 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
411 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
412 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
413 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
414 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
417 #define SIZE_CHECK(sname, stype, tfield) do { \
418 s1 = fnum_find(sname); \
419 if (s1 && s1->stype.out.tfield != correct_size) { \
420 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
421 (uint_t)s1->stype.out.tfield, \
422 (uint_t)correct_size); \
425 s1 = fname_find(sname); \
426 if (s1 && s1->stype.out.tfield != correct_size) { \
427 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
428 (uint_t)s1->stype.out.tfield, \
429 (uint_t)correct_size); \
433 s1 = fnum_find("STANDARD_INFO");
434 correct_size = s1->standard_info.out.size;
435 printf("size: %u\n", (uint_t)correct_size);
437 SIZE_CHECK("GETATTR", getattr, size);
438 SIZE_CHECK("GETATTRE", getattre, size);
439 SIZE_CHECK("STANDARD", standard, size);
440 SIZE_CHECK("EA_SIZE", ea_size, size);
441 SIZE_CHECK("STANDARD_INFO", standard_info, size);
442 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
443 SIZE_CHECK("ALL_INFO", all_info, size);
444 SIZE_CHECK("ALL_INFORMATION", all_info, size);
445 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
446 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
447 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
449 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
450 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
454 s1 = fnum_find("STANDARD_INFO");
455 correct_size = s1->standard_info.out.alloc_size;
456 printf("alloc_size: %u\n", (uint_t)correct_size);
458 SIZE_CHECK("GETATTRE", getattre, alloc_size);
459 SIZE_CHECK("STANDARD", standard, alloc_size);
460 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
461 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
462 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
463 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
464 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
465 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
467 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
468 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
471 #define ATTRIB_CHECK(sname, stype, tfield) do { \
472 s1 = fnum_find(sname); \
473 if (s1 && s1->stype.out.tfield != correct_attrib) { \
474 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
475 (uint_t)s1->stype.out.tfield, \
476 (uint_t)correct_attrib); \
479 s1 = fname_find(sname); \
480 if (s1 && s1->stype.out.tfield != correct_attrib) { \
481 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
482 (uint_t)s1->stype.out.tfield, \
483 (uint_t)correct_attrib); \
487 s1 = fnum_find("BASIC_INFO");
488 correct_attrib = s1->basic_info.out.attrib;
489 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
491 ATTRIB_CHECK("GETATTR", getattr, attrib);
492 ATTRIB_CHECK("GETATTRE", getattre, attrib);
493 ATTRIB_CHECK("STANDARD", standard, attrib);
494 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
495 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
496 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
497 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
498 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
499 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
500 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
502 correct_name = fname;
503 printf("name: %s\n", correct_name);
505 #define NAME_CHECK(sname, stype, tfield, flags) do { \
506 s1 = fnum_find(sname); \
507 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
508 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
509 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
510 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
513 s1 = fname_find(sname); \
514 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
515 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
516 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
517 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
521 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
522 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
524 /* the ALL_INFO file name is the full path on the filesystem */
525 s1 = fnum_find("ALL_INFO");
526 if (s1 && !s1->all_info.out.fname.s) {
527 printf("ALL_INFO didn't give a filename\n");
530 if (s1 && s1->all_info.out.fname.s) {
531 char *p = strrchr(s1->all_info.out.fname.s, '\\');
533 printf("Not a full path in all_info/fname? - '%s'\n",
534 s1->all_info.out.fname.s);
537 if (strcmp_safe(correct_name, p) != 0) {
538 printf("incorrect basename in all_info/fname - '%s'\n",
539 s1->all_info.out.fname.s);
543 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, cli)) {
544 printf("Should not null terminate all_info/fname\n");
549 s1 = fnum_find("ALT_NAME_INFO");
550 correct_name = s1->alt_name_info.out.fname.s;
551 printf("alt_name: %s\n", correct_name);
553 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
554 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
556 /* and make sure we can open by alternate name */
557 smbcli_close(cli->tree, fnum);
558 fnum = smbcli_nt_create_full(cli->tree, correct_name, 0,
560 FILE_ATTRIBUTE_NORMAL,
561 NTCREATEX_SHARE_ACCESS_DELETE|
562 NTCREATEX_SHARE_ACCESS_READ|
563 NTCREATEX_SHARE_ACCESS_WRITE,
564 NTCREATEX_DISP_OVERWRITE_IF,
567 printf("Unable to open by alt_name - %s\n", smbcli_errstr(cli->tree));
572 correct_name = "::$DATA";
573 printf("stream_name: %s\n", correct_name);
575 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
576 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
579 /* make sure the EAs look right */
580 s1 = fnum_find("ALL_EAS");
581 s2 = fnum_find("ALL_INFO");
583 for (i=0;i<s1->all_eas.out.num_eas;i++) {
584 printf(" flags=%d %s=%*.*s\n",
585 s1->all_eas.out.eas[i].flags,
586 s1->all_eas.out.eas[i].name.s,
587 (int)s1->all_eas.out.eas[i].value.length,
588 (int)s1->all_eas.out.eas[i].value.length,
589 s1->all_eas.out.eas[i].value.data);
593 if (s1->all_eas.out.num_eas == 0) {
594 if (s2->all_info.out.ea_size != 0) {
595 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
596 s2->all_info.out.ea_size);
599 if (s2->all_info.out.ea_size !=
600 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
601 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
602 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
603 s2->all_info.out.ea_size);
607 s2 = fname_find("ALL_EAS");
609 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
610 for (i=0;i<s1->all_eas.out.num_eas;i++) {
611 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
612 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
613 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
617 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
618 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
619 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
620 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
621 #stype1, #tfield1, #stype2, #tfield2, \
622 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
625 s1 = fname_find(sname1); s2 = fname_find(sname2); \
626 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
627 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
628 #stype1, #tfield1, #stype2, #tfield2, \
629 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
632 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
633 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
634 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
635 #stype1, #tfield1, #stype2, #tfield2, \
636 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
639 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
640 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
641 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
642 #stype1, #tfield1, #stype2, #tfield2, \
643 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
647 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
648 "ALL_INFO", all_info, delete_pending);
649 VAL_CHECK("STANDARD_INFO", standard_info, directory,
650 "ALL_INFO", all_info, directory);
651 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
652 "ALL_INFO", all_info, nlink);
653 VAL_CHECK("EA_INFO", ea_info, ea_size,
654 "ALL_INFO", all_info, ea_size);
655 VAL_CHECK("EA_SIZE", ea_size, ea_size,
656 "ALL_INFO", all_info, ea_size);
659 #define NAME_PATH_CHECK(sname, stype, field) do { \
660 s1 = fname_find(sname); s2 = fnum_find(sname); \
662 VAL_EQUAL(stype, field, stype, field); \
667 s1 = fnum_find("INTERNAL_INFORMATION");
669 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
672 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
673 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
675 printf("fnum pos = %.0f, fname pos = %.0f\n",
676 (double)s2->position_information.out.position,
677 (double)s1->position_information.out.position );
679 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
680 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
681 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
682 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
685 /* these are expected to differ */
686 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
689 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
690 s1 = fnum_find(sname); \
691 if (s1 && s1->stype.out.tfield != 0) { \
692 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
694 (uint_t)s1->stype.out.tfield); \
696 s1 = fname_find(sname); \
697 if (s1 && s1->stype.out.tfield != 0) { \
698 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
700 (uint_t)s1->stype.out.tfield); \
703 /* now get a bit fancier .... */
705 /* when we set the delete disposition then the link count should drop
706 to 0 and delete_pending should be 1 */
710 smbcli_close(cli->tree, fnum);
711 smbcli_unlink(cli->tree, fname);
713 torture_close_connection(cli);
714 talloc_free(mem_ctx);