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"
25 #include "torture/util.h"
29 enum smb_fileinfo_level level;
31 uint_t only_handles:1;
32 uint32_t capability_mask;
33 NTSTATUS fnum_status, fname_status;
34 union smb_fileinfo fnum_finfo, fname_finfo;
36 { "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
37 { "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
38 { "STANDARD", RAW_FILEINFO_STANDARD, },
39 { "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
40 { "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
41 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
42 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
43 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
44 { "EA_INFO", RAW_FILEINFO_EA_INFO, },
45 { "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
46 { "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
47 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
48 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
49 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
50 { "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
51 { "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
52 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
53 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
54 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
55 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
56 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
57 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
58 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
59 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
60 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
61 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
62 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
63 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
64 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
65 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
66 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
71 compare a dos time (2 second resolution) to a nt time
73 static int dos_nt_time_cmp(time_t t, NTTIME nt)
75 time_t t2 = nt_time_to_unix(nt);
76 if (abs(t2 - t) <= 2) return 0;
82 find a level in the levels[] table
84 static union smb_fileinfo *fnum_find(const char *name)
87 for (i=0; levels[i].name; i++) {
88 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
89 strcmp(name, levels[i].name) == 0 &&
90 !levels[i].only_paths) {
91 return &levels[i].fnum_finfo;
98 find a level in the levels[] table
100 static union smb_fileinfo *fname_find(const char *name)
103 for (i=0; levels[i].name; i++) {
104 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
105 strcmp(name, levels[i].name) == 0 &&
106 !levels[i].only_handles) {
107 return &levels[i].fname_finfo;
113 /* local macros to make the code below more readable */
114 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
115 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
116 #n1, #v1, (uint_t)s1->n1.out.v1, \
117 #n2, #v2, (uint_t)s2->n2.out.v2, \
118 __FILE__, __LINE__); \
122 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
123 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
124 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
125 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
126 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
127 __FILE__, __LINE__); \
131 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
132 printf("%s/%s != %s/%s at %s(%d)\n", \
135 __FILE__, __LINE__); \
139 /* used to find hints on unknown values - and to make sure
142 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
143 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
145 (uint_t)s1->n1.out.v1, \
146 (uint_t)s1->n1.out.v1, \
147 __FILE__, __LINE__); \
152 /* basic testing of all RAW_FILEINFO_* calls
153 for each call we test that it succeeds, and where possible test
154 for consistency between the calls.
156 BOOL torture_raw_qfileinfo(struct torture_context *torture)
158 struct smbcli_state *cli;
162 union smb_fileinfo *s1, *s2;
165 const char *fname = "\\torture_qfileinfo.txt";
167 uint64_t correct_size;
168 uint32_t correct_attrib;
169 const char *correct_name;
170 BOOL skip_streams = False;
172 if (!torture_open_connection(&cli, 0)) {
176 mem_ctx = talloc_init("torture_qfileinfo");
178 fnum = create_complex_file(cli, mem_ctx, fname);
180 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
186 /* scan all the fileinfo and pathinfo levels */
187 for (i=0; levels[i].name; i++) {
188 if (!levels[i].only_paths) {
189 levels[i].fnum_finfo.generic.level = levels[i].level;
190 levels[i].fnum_finfo.generic.in.file.fnum = fnum;
191 levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
192 &levels[i].fnum_finfo);
195 if (!levels[i].only_handles) {
196 levels[i].fname_finfo.generic.level = levels[i].level;
197 levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
198 levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
199 &levels[i].fname_finfo);
203 /* check for completely broken levels */
204 for (count=i=0; levels[i].name; i++) {
205 uint32_t cap = cli->transport->negotiate.capabilities;
206 /* see if this server claims to support this level */
207 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
211 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
212 printf("ERROR: level %s failed - %s\n",
213 levels[i].name, nt_errstr(levels[i].fnum_status));
216 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
217 printf("ERROR: level %s failed - %s\n",
218 levels[i].name, nt_errstr(levels[i].fname_status));
225 printf("%d levels failed\n", count);
227 printf("too many level failures - giving up\n");
232 /* see if we can do streams */
233 s1 = fnum_find("STREAM_INFO");
234 if (!s1 || s1->stream_info.out.num_streams == 0) {
235 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
236 s1 ? s1->stream_info.out.num_streams : -1);
241 /* this code is incredibly repititive but doesn't lend itself to loops, so
242 we use lots of macros to make it less painful */
244 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
245 this code to fail, but we need to check it for completeness */
249 #define ALIAS_CHECK(sname1, sname2) \
251 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
252 if (s1 && s2) { INFO_CHECK } \
253 s1 = fname_find(sname1); s2 = fname_find(sname2); \
254 if (s1 && s2) { INFO_CHECK } \
255 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
256 if (s1 && s2) { INFO_CHECK } \
260 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
261 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
262 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
263 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
264 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
266 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
270 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
271 VAL_EQUAL(standard_info, size, standard_info, size); \
272 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
273 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
274 VAL_EQUAL(standard_info, directory, standard_info, directory);
276 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
280 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
282 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
286 STR_EQUAL(name_info, fname, name_info, fname);
288 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
292 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
293 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
294 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
295 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
296 VAL_EQUAL(all_info, attrib, all_info, attrib); \
297 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
298 VAL_EQUAL(all_info, size, all_info, size); \
299 VAL_EQUAL(all_info, nlink, all_info, nlink); \
300 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
301 VAL_EQUAL(all_info, directory, all_info, directory); \
302 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
303 STR_EQUAL(all_info, fname, all_info, fname);
305 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
309 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
310 VAL_EQUAL(compression_info, format, compression_info, format); \
311 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
312 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
313 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
315 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
320 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
322 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
325 #define TIME_CHECK_NT(sname, stype, tfield) do { \
326 s1 = fnum_find(sname); \
327 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
328 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
329 nt_time_string(mem_ctx, s1->stype.out.tfield), \
330 nt_time_string(mem_ctx, correct_time)); \
333 s1 = fname_find(sname); \
334 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
335 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
336 nt_time_string(mem_ctx, s1->stype.out.tfield), \
337 nt_time_string(mem_ctx, correct_time)); \
341 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
342 s1 = fnum_find(sname); \
343 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
344 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
345 timestring(mem_ctx, s1->stype.out.tfield), \
346 nt_time_string(mem_ctx, correct_time)); \
349 s1 = fname_find(sname); \
350 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
351 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
352 timestring(mem_ctx, s1->stype.out.tfield), \
353 nt_time_string(mem_ctx, correct_time)); \
358 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
359 s1 = fnum_find(sname); \
360 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
361 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
362 timestring(mem_ctx, s1->stype.out.tfield), \
363 nt_time_string(mem_ctx, correct_time)); \
366 s1 = fname_find(sname); \
367 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
368 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
369 timestring(mem_ctx, s1->stype.out.tfield), \
370 nt_time_string(mem_ctx, correct_time)); \
375 /* now check that all the times that are supposed to be equal are correct */
376 s1 = fnum_find("BASIC_INFO");
377 correct_time = s1->basic_info.out.create_time;
378 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
380 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
381 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
382 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
383 TIME_CHECK_DOS("STANDARD", standard, create_time);
384 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
385 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
386 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
388 s1 = fnum_find("BASIC_INFO");
389 correct_time = s1->basic_info.out.access_time;
390 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
392 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
393 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
394 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
395 TIME_CHECK_DOS("STANDARD", standard, access_time);
396 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
397 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
398 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
400 s1 = fnum_find("BASIC_INFO");
401 correct_time = s1->basic_info.out.write_time;
402 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
404 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
405 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
406 TIME_CHECK_DOS("GETATTR", getattr, write_time);
407 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
408 TIME_CHECK_DOS("STANDARD", standard, write_time);
409 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
410 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
411 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
413 s1 = fnum_find("BASIC_INFO");
414 correct_time = s1->basic_info.out.change_time;
415 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
417 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
418 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
419 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
420 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
423 #define SIZE_CHECK(sname, stype, tfield) do { \
424 s1 = fnum_find(sname); \
425 if (s1 && s1->stype.out.tfield != correct_size) { \
426 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
427 (uint_t)s1->stype.out.tfield, \
428 (uint_t)correct_size); \
431 s1 = fname_find(sname); \
432 if (s1 && s1->stype.out.tfield != correct_size) { \
433 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
434 (uint_t)s1->stype.out.tfield, \
435 (uint_t)correct_size); \
439 s1 = fnum_find("STANDARD_INFO");
440 correct_size = s1->standard_info.out.size;
441 printf("size: %u\n", (uint_t)correct_size);
443 SIZE_CHECK("GETATTR", getattr, size);
444 SIZE_CHECK("GETATTRE", getattre, size);
445 SIZE_CHECK("STANDARD", standard, size);
446 SIZE_CHECK("EA_SIZE", ea_size, size);
447 SIZE_CHECK("STANDARD_INFO", standard_info, size);
448 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
449 SIZE_CHECK("ALL_INFO", all_info, size);
450 SIZE_CHECK("ALL_INFORMATION", all_info, size);
451 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
452 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
453 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
455 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
456 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
460 s1 = fnum_find("STANDARD_INFO");
461 correct_size = s1->standard_info.out.alloc_size;
462 printf("alloc_size: %u\n", (uint_t)correct_size);
464 SIZE_CHECK("GETATTRE", getattre, alloc_size);
465 SIZE_CHECK("STANDARD", standard, alloc_size);
466 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
467 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
468 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
469 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
470 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
471 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
473 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
474 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
477 #define ATTRIB_CHECK(sname, stype, tfield) do { \
478 s1 = fnum_find(sname); \
479 if (s1 && s1->stype.out.tfield != correct_attrib) { \
480 printf("(%d) handle %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); \
485 s1 = fname_find(sname); \
486 if (s1 && s1->stype.out.tfield != correct_attrib) { \
487 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
488 (uint_t)s1->stype.out.tfield, \
489 (uint_t)correct_attrib); \
493 s1 = fnum_find("BASIC_INFO");
494 correct_attrib = s1->basic_info.out.attrib;
495 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
497 ATTRIB_CHECK("GETATTR", getattr, attrib);
498 ATTRIB_CHECK("GETATTRE", getattre, attrib);
499 ATTRIB_CHECK("STANDARD", standard, attrib);
500 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
501 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
502 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
503 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
504 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
505 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
506 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
508 correct_name = fname;
509 printf("name: %s\n", correct_name);
511 #define NAME_CHECK(sname, stype, tfield, flags) do { \
512 s1 = fnum_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) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
516 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
519 s1 = fname_find(sname); \
520 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
521 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
522 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
523 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
527 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
528 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
530 /* the ALL_INFO file name is the full path on the filesystem */
531 s1 = fnum_find("ALL_INFO");
532 if (s1 && !s1->all_info.out.fname.s) {
533 printf("ALL_INFO didn't give a filename\n");
536 if (s1 && s1->all_info.out.fname.s) {
537 char *p = strrchr(s1->all_info.out.fname.s, '\\');
539 printf("Not a full path in all_info/fname? - '%s'\n",
540 s1->all_info.out.fname.s);
543 if (strcmp_safe(correct_name, p) != 0) {
544 printf("incorrect basename in all_info/fname - '%s'\n",
545 s1->all_info.out.fname.s);
549 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, cli)) {
550 printf("Should not null terminate all_info/fname\n");
555 s1 = fnum_find("ALT_NAME_INFO");
556 correct_name = s1->alt_name_info.out.fname.s;
557 printf("alt_name: %s\n", correct_name);
559 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
560 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
562 /* and make sure we can open by alternate name */
563 smbcli_close(cli->tree, fnum);
564 fnum = smbcli_nt_create_full(cli->tree, correct_name, 0,
566 FILE_ATTRIBUTE_NORMAL,
567 NTCREATEX_SHARE_ACCESS_DELETE|
568 NTCREATEX_SHARE_ACCESS_READ|
569 NTCREATEX_SHARE_ACCESS_WRITE,
570 NTCREATEX_DISP_OVERWRITE_IF,
573 printf("Unable to open by alt_name - %s\n", smbcli_errstr(cli->tree));
578 correct_name = "::$DATA";
579 printf("stream_name: %s\n", correct_name);
581 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
582 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
585 /* make sure the EAs look right */
586 s1 = fnum_find("ALL_EAS");
587 s2 = fnum_find("ALL_INFO");
589 for (i=0;i<s1->all_eas.out.num_eas;i++) {
590 printf(" flags=%d %s=%*.*s\n",
591 s1->all_eas.out.eas[i].flags,
592 s1->all_eas.out.eas[i].name.s,
593 (int)s1->all_eas.out.eas[i].value.length,
594 (int)s1->all_eas.out.eas[i].value.length,
595 s1->all_eas.out.eas[i].value.data);
599 if (s1->all_eas.out.num_eas == 0) {
600 if (s2->all_info.out.ea_size != 0) {
601 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
602 s2->all_info.out.ea_size);
605 if (s2->all_info.out.ea_size !=
606 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
607 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
608 (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
609 (int)s2->all_info.out.ea_size);
613 s2 = fname_find("ALL_EAS");
615 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
616 for (i=0;i<s1->all_eas.out.num_eas;i++) {
617 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
618 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
619 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
623 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
624 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
625 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
626 printf("(%d) handle %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 = fname_find(sname1); s2 = fname_find(sname2); \
632 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
633 printf("(%d) path %s/%s != %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 = fnum_find(sname1); s2 = fname_find(sname2); \
639 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
640 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
641 #stype1, #tfield1, #stype2, #tfield2, \
642 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
645 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
646 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
647 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
648 #stype1, #tfield1, #stype2, #tfield2, \
649 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
653 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
654 "ALL_INFO", all_info, delete_pending);
655 VAL_CHECK("STANDARD_INFO", standard_info, directory,
656 "ALL_INFO", all_info, directory);
657 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
658 "ALL_INFO", all_info, nlink);
659 VAL_CHECK("EA_INFO", ea_info, ea_size,
660 "ALL_INFO", all_info, ea_size);
661 VAL_CHECK("EA_SIZE", ea_size, ea_size,
662 "ALL_INFO", all_info, ea_size);
665 #define NAME_PATH_CHECK(sname, stype, field) do { \
666 s1 = fname_find(sname); s2 = fnum_find(sname); \
668 VAL_EQUAL(stype, field, stype, field); \
673 s1 = fnum_find("INTERNAL_INFORMATION");
675 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
678 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
679 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
681 printf("fnum pos = %.0f, fname pos = %.0f\n",
682 (double)s2->position_information.out.position,
683 (double)s1->position_information.out.position );
685 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
686 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
687 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
688 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
691 /* these are expected to differ */
692 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
696 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
697 s1 = fnum_find(sname); \
698 if (s1 && s1->stype.out.tfield != 0) { \
699 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
701 (uint_t)s1->stype.out.tfield); \
703 s1 = fname_find(sname); \
704 if (s1 && s1->stype.out.tfield != 0) { \
705 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
707 (uint_t)s1->stype.out.tfield); \
710 /* now get a bit fancier .... */
712 /* when we set the delete disposition then the link count should drop
713 to 0 and delete_pending should be 1 */
717 smbcli_close(cli->tree, fnum);
718 smbcli_unlink(cli->tree, fname);
720 torture_close_connection(cli);
721 talloc_free(mem_ctx);