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"
24 #include "libcli/libcli.h"
28 enum smb_fileinfo_level level;
30 uint_t only_handles:1;
31 uint32_t capability_mask;
32 NTSTATUS fnum_status, fname_status;
33 union smb_fileinfo fnum_finfo, fname_finfo;
35 { "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
36 { "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
37 { "STANDARD", RAW_FILEINFO_STANDARD, },
38 { "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
39 { "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
40 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
41 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
42 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
43 { "EA_INFO", RAW_FILEINFO_EA_INFO, },
44 { "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
45 { "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
46 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
47 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
48 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
49 { "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
50 { "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
51 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
52 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
53 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
54 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
55 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
56 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
57 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
58 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
59 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
60 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
61 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
62 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
63 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
64 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
65 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
70 compare a dos time (2 second resolution) to a nt time
72 static int dos_nt_time_cmp(time_t t, NTTIME nt)
74 time_t t2 = nt_time_to_unix(nt);
75 if (ABS(t2 - t) <= 2) return 0;
81 find a level in the levels[] table
83 static union smb_fileinfo *fnum_find(const char *name)
86 for (i=0; levels[i].name; i++) {
87 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
88 strcmp(name, levels[i].name) == 0 &&
89 !levels[i].only_paths) {
90 return &levels[i].fnum_finfo;
97 find a level in the levels[] table
99 static union smb_fileinfo *fname_find(const char *name)
102 for (i=0; levels[i].name; i++) {
103 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
104 strcmp(name, levels[i].name) == 0 &&
105 !levels[i].only_handles) {
106 return &levels[i].fname_finfo;
112 /* local macros to make the code below more readable */
113 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
114 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
115 #n1, #v1, (uint_t)s1->n1.out.v1, \
116 #n2, #v2, (uint_t)s2->n2.out.v2, \
117 __FILE__, __LINE__); \
121 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
122 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
123 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
124 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
125 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
126 __FILE__, __LINE__); \
130 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
131 printf("%s/%s != %s/%s at %s(%d)\n", \
134 __FILE__, __LINE__); \
138 /* used to find hints on unknown values - and to make sure
140 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
141 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
143 (uint_t)s1->n1.out.v1, \
144 (uint_t)s1->n1.out.v1, \
145 __FILE__, __LINE__); \
149 /* basic testing of all RAW_FILEINFO_* calls
150 for each call we test that it succeeds, and where possible test
151 for consistency between the calls.
153 BOOL torture_raw_qfileinfo(void)
155 struct smbcli_state *cli;
159 union smb_fileinfo *s1, *s2;
162 const char *fname = "\\torture_qfileinfo.txt";
164 uint64_t correct_size;
165 uint32_t correct_attrib;
166 const char *correct_name;
167 BOOL skip_streams = False;
169 if (!torture_open_connection(&cli)) {
173 mem_ctx = talloc_init("torture_qfileinfo");
175 fnum = create_complex_file(cli, mem_ctx, fname);
177 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
183 /* scan all the fileinfo and pathinfo levels */
184 for (i=0; levels[i].name; i++) {
185 if (!levels[i].only_paths) {
186 levels[i].fnum_finfo.generic.level = levels[i].level;
187 levels[i].fnum_finfo.generic.in.fnum = fnum;
188 levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
189 &levels[i].fnum_finfo);
192 if (!levels[i].only_handles) {
193 levels[i].fname_finfo.generic.level = levels[i].level;
194 levels[i].fname_finfo.generic.in.fname = talloc_strdup(mem_ctx, fname);
195 levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
196 &levels[i].fname_finfo);
200 /* check for completely broken levels */
201 for (count=i=0; levels[i].name; i++) {
202 uint32_t cap = cli->transport->negotiate.capabilities;
203 /* see if this server claims to support this level */
204 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
208 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
209 printf("ERROR: level %s failed - %s\n",
210 levels[i].name, nt_errstr(levels[i].fnum_status));
213 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
214 printf("ERROR: level %s failed - %s\n",
215 levels[i].name, nt_errstr(levels[i].fname_status));
222 printf("%d levels failed\n", count);
224 printf("too many level failures - giving up\n");
229 /* see if we can do streams */
230 s1 = fnum_find("STREAM_INFO");
231 if (!s1 || s1->stream_info.out.num_streams == 0) {
232 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
233 s1 ? s1->stream_info.out.num_streams : -1);
238 /* this code is incredibly repititive but doesn't lend itself to loops, so
239 we use lots of macros to make it less painful */
241 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
242 this code to fail, but we need to check it for completeness */
246 #define ALIAS_CHECK(sname1, sname2) \
248 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
249 if (s1 && s2) { INFO_CHECK } \
250 s1 = fname_find(sname1); s2 = fname_find(sname2); \
251 if (s1 && s2) { INFO_CHECK } \
252 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
253 if (s1 && s2) { INFO_CHECK } \
257 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
258 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
259 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
260 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
261 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
263 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
267 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
268 VAL_EQUAL(standard_info, size, standard_info, size); \
269 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
270 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
271 VAL_EQUAL(standard_info, directory, standard_info, directory);
273 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
277 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
279 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
283 STR_EQUAL(name_info, fname, name_info, fname);
285 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
289 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
290 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
291 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
292 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
293 VAL_EQUAL(all_info, attrib, all_info, attrib); \
294 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
295 VAL_EQUAL(all_info, size, all_info, size); \
296 VAL_EQUAL(all_info, nlink, all_info, nlink); \
297 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
298 VAL_EQUAL(all_info, directory, all_info, directory); \
299 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
300 STR_EQUAL(all_info, fname, all_info, fname);
302 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
306 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
307 VAL_EQUAL(compression_info, format, compression_info, format); \
308 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
309 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
310 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
312 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
317 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
319 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
322 #define TIME_CHECK_NT(sname, stype, tfield) do { \
323 s1 = fnum_find(sname); \
324 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
325 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
326 nt_time_string(mem_ctx, s1->stype.out.tfield), \
327 nt_time_string(mem_ctx, correct_time)); \
330 s1 = fname_find(sname); \
331 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
332 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
333 nt_time_string(mem_ctx, s1->stype.out.tfield), \
334 nt_time_string(mem_ctx, correct_time)); \
338 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
339 s1 = fnum_find(sname); \
340 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
341 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
342 timestring(mem_ctx, s1->stype.out.tfield), \
343 nt_time_string(mem_ctx, correct_time)); \
346 s1 = fname_find(sname); \
347 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
348 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
349 timestring(mem_ctx, s1->stype.out.tfield), \
350 nt_time_string(mem_ctx, correct_time)); \
354 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
355 s1 = fnum_find(sname); \
356 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
357 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
358 timestring(mem_ctx, s1->stype.out.tfield), \
359 nt_time_string(mem_ctx, correct_time)); \
362 s1 = fname_find(sname); \
363 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
364 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
365 timestring(mem_ctx, s1->stype.out.tfield), \
366 nt_time_string(mem_ctx, correct_time)); \
370 /* now check that all the times that are supposed to be equal are correct */
371 s1 = fnum_find("BASIC_INFO");
372 correct_time = s1->basic_info.out.create_time;
373 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
375 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
376 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
377 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
378 TIME_CHECK_DOS("STANDARD", standard, create_time);
379 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
380 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
381 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
383 s1 = fnum_find("BASIC_INFO");
384 correct_time = s1->basic_info.out.access_time;
385 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
387 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
388 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
389 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
390 TIME_CHECK_DOS("STANDARD", standard, access_time);
391 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
392 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
393 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
395 s1 = fnum_find("BASIC_INFO");
396 correct_time = s1->basic_info.out.write_time;
397 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
399 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
400 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
401 TIME_CHECK_DOS("GETATTR", getattr, write_time);
402 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
403 TIME_CHECK_DOS("STANDARD", standard, write_time);
404 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
405 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
406 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
408 s1 = fnum_find("BASIC_INFO");
409 correct_time = s1->basic_info.out.change_time;
410 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
412 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
413 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
414 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
415 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
418 #define SIZE_CHECK(sname, stype, tfield) do { \
419 s1 = fnum_find(sname); \
420 if (s1 && s1->stype.out.tfield != correct_size) { \
421 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
422 (uint_t)s1->stype.out.tfield, \
423 (uint_t)correct_size); \
426 s1 = fname_find(sname); \
427 if (s1 && s1->stype.out.tfield != correct_size) { \
428 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
429 (uint_t)s1->stype.out.tfield, \
430 (uint_t)correct_size); \
434 s1 = fnum_find("STANDARD_INFO");
435 correct_size = s1->standard_info.out.size;
436 printf("size: %u\n", (uint_t)correct_size);
438 SIZE_CHECK("GETATTR", getattr, size);
439 SIZE_CHECK("GETATTRE", getattre, size);
440 SIZE_CHECK("STANDARD", standard, size);
441 SIZE_CHECK("EA_SIZE", ea_size, size);
442 SIZE_CHECK("STANDARD_INFO", standard_info, size);
443 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
444 SIZE_CHECK("ALL_INFO", all_info, size);
445 SIZE_CHECK("ALL_INFORMATION", all_info, size);
446 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
447 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
448 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
450 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
451 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
455 s1 = fnum_find("STANDARD_INFO");
456 correct_size = s1->standard_info.out.alloc_size;
457 printf("alloc_size: %u\n", (uint_t)correct_size);
459 SIZE_CHECK("GETATTRE", getattre, alloc_size);
460 SIZE_CHECK("STANDARD", standard, alloc_size);
461 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
462 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
463 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
464 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
465 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
466 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
468 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
469 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
472 #define ATTRIB_CHECK(sname, stype, tfield) do { \
473 s1 = fnum_find(sname); \
474 if (s1 && s1->stype.out.tfield != correct_attrib) { \
475 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
476 (uint_t)s1->stype.out.tfield, \
477 (uint_t)correct_attrib); \
480 s1 = fname_find(sname); \
481 if (s1 && s1->stype.out.tfield != correct_attrib) { \
482 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
483 (uint_t)s1->stype.out.tfield, \
484 (uint_t)correct_attrib); \
488 s1 = fnum_find("BASIC_INFO");
489 correct_attrib = s1->basic_info.out.attrib;
490 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
492 ATTRIB_CHECK("GETATTR", getattr, attrib);
493 ATTRIB_CHECK("GETATTRE", getattre, attrib);
494 ATTRIB_CHECK("STANDARD", standard, attrib);
495 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
496 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
497 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
498 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
499 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
500 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
501 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
503 correct_name = fname;
504 printf("name: %s\n", correct_name);
506 #define NAME_CHECK(sname, stype, tfield, flags) do { \
507 s1 = fnum_find(sname); \
508 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
509 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
510 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
511 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
514 s1 = fname_find(sname); \
515 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
516 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
517 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
518 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
522 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
523 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
525 /* the ALL_INFO file name is the full path on the filesystem */
526 s1 = fnum_find("ALL_INFO");
527 if (s1 && !s1->all_info.out.fname.s) {
528 printf("ALL_INFO didn't give a filename\n");
531 if (s1 && s1->all_info.out.fname.s) {
532 char *p = strrchr(s1->all_info.out.fname.s, '\\');
534 printf("Not a full path in all_info/fname? - '%s'\n",
535 s1->all_info.out.fname.s);
538 if (strcmp_safe(correct_name, p) != 0) {
539 printf("incorrect basename in all_info/fname - '%s'\n",
540 s1->all_info.out.fname.s);
544 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, cli)) {
545 printf("Should not null terminate all_info/fname\n");
550 s1 = fnum_find("ALT_NAME_INFO");
551 correct_name = s1->alt_name_info.out.fname.s;
552 printf("alt_name: %s\n", correct_name);
554 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
555 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
557 /* and make sure we can open by alternate name */
558 smbcli_close(cli->tree, fnum);
559 fnum = smbcli_nt_create_full(cli->tree, correct_name, 0,
561 FILE_ATTRIBUTE_NORMAL,
562 NTCREATEX_SHARE_ACCESS_DELETE|
563 NTCREATEX_SHARE_ACCESS_READ|
564 NTCREATEX_SHARE_ACCESS_WRITE,
565 NTCREATEX_DISP_OVERWRITE_IF,
568 printf("Unable to open by alt_name - %s\n", smbcli_errstr(cli->tree));
573 correct_name = "::$DATA";
574 printf("stream_name: %s\n", correct_name);
576 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
577 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
580 /* make sure the EAs look right */
581 s1 = fnum_find("ALL_EAS");
582 s2 = fnum_find("ALL_INFO");
584 for (i=0;i<s1->all_eas.out.num_eas;i++) {
585 printf(" flags=%d %s=%*.*s\n",
586 s1->all_eas.out.eas[i].flags,
587 s1->all_eas.out.eas[i].name.s,
588 (int)s1->all_eas.out.eas[i].value.length,
589 (int)s1->all_eas.out.eas[i].value.length,
590 s1->all_eas.out.eas[i].value.data);
594 if (s1->all_eas.out.num_eas == 0) {
595 if (s2->all_info.out.ea_size != 0) {
596 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
597 s2->all_info.out.ea_size);
600 if (s2->all_info.out.ea_size !=
601 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
602 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
603 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
604 s2->all_info.out.ea_size);
608 s2 = fname_find("ALL_EAS");
610 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
611 for (i=0;i<s1->all_eas.out.num_eas;i++) {
612 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
613 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
614 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
618 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
619 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
620 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
621 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
622 #stype1, #tfield1, #stype2, #tfield2, \
623 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
626 s1 = fname_find(sname1); s2 = fname_find(sname2); \
627 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
628 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
629 #stype1, #tfield1, #stype2, #tfield2, \
630 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
633 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
634 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
635 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
636 #stype1, #tfield1, #stype2, #tfield2, \
637 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
640 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
641 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
642 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
643 #stype1, #tfield1, #stype2, #tfield2, \
644 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
648 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
649 "ALL_INFO", all_info, delete_pending);
650 VAL_CHECK("STANDARD_INFO", standard_info, directory,
651 "ALL_INFO", all_info, directory);
652 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
653 "ALL_INFO", all_info, nlink);
654 VAL_CHECK("EA_INFO", ea_info, ea_size,
655 "ALL_INFO", all_info, ea_size);
656 VAL_CHECK("EA_SIZE", ea_size, ea_size,
657 "ALL_INFO", all_info, ea_size);
660 #define NAME_PATH_CHECK(sname, stype, field) do { \
661 s1 = fname_find(sname); s2 = fnum_find(sname); \
663 VAL_EQUAL(stype, field, stype, field); \
668 s1 = fnum_find("INTERNAL_INFORMATION");
670 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
673 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
674 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
676 printf("fnum pos = %.0f, fname pos = %.0f\n",
677 (double)s2->position_information.out.position,
678 (double)s1->position_information.out.position );
680 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
681 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
682 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
683 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
686 /* these are expected to differ */
687 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
690 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
691 s1 = fnum_find(sname); \
692 if (s1 && s1->stype.out.tfield != 0) { \
693 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
695 (uint_t)s1->stype.out.tfield); \
697 s1 = fname_find(sname); \
698 if (s1 && s1->stype.out.tfield != 0) { \
699 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
701 (uint_t)s1->stype.out.tfield); \
704 /* now get a bit fancier .... */
706 /* when we set the delete disposition then the link count should drop
707 to 0 and delete_pending should be 1 */
711 smbcli_close(cli->tree, fnum);
712 smbcli_unlink(cli->tree, fname);
714 torture_close_connection(cli);
715 talloc_free(mem_ctx);