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
141 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
142 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
144 (uint_t)s1->n1.out.v1, \
145 (uint_t)s1->n1.out.v1, \
146 __FILE__, __LINE__); \
150 /* basic testing of all RAW_FILEINFO_* calls
151 for each call we test that it succeeds, and where possible test
152 for consistency between the calls.
154 BOOL torture_raw_qfileinfo(void)
156 struct smbcli_state *cli;
160 union smb_fileinfo *s1, *s2;
163 const char *fname = "\\torture_qfileinfo.txt";
165 uint64_t correct_size;
166 uint32_t correct_attrib;
167 const char *correct_name;
168 BOOL skip_streams = False;
170 if (!torture_open_connection(&cli)) {
174 mem_ctx = talloc_init("torture_qfileinfo");
176 fnum = create_complex_file(cli, mem_ctx, fname);
178 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
184 /* scan all the fileinfo and pathinfo levels */
185 for (i=0; levels[i].name; i++) {
186 if (!levels[i].only_paths) {
187 levels[i].fnum_finfo.generic.level = levels[i].level;
188 levels[i].fnum_finfo.generic.in.file.fnum = fnum;
189 levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
190 &levels[i].fnum_finfo);
193 if (!levels[i].only_handles) {
194 levels[i].fname_finfo.generic.level = levels[i].level;
195 levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
196 levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
197 &levels[i].fname_finfo);
201 /* check for completely broken levels */
202 for (count=i=0; levels[i].name; i++) {
203 uint32_t cap = cli->transport->negotiate.capabilities;
204 /* see if this server claims to support this level */
205 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
209 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
210 printf("ERROR: level %s failed - %s\n",
211 levels[i].name, nt_errstr(levels[i].fnum_status));
214 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
215 printf("ERROR: level %s failed - %s\n",
216 levels[i].name, nt_errstr(levels[i].fname_status));
223 printf("%d levels failed\n", count);
225 printf("too many level failures - giving up\n");
230 /* see if we can do streams */
231 s1 = fnum_find("STREAM_INFO");
232 if (!s1 || s1->stream_info.out.num_streams == 0) {
233 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
234 s1 ? s1->stream_info.out.num_streams : -1);
239 /* this code is incredibly repititive but doesn't lend itself to loops, so
240 we use lots of macros to make it less painful */
242 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
243 this code to fail, but we need to check it for completeness */
247 #define ALIAS_CHECK(sname1, sname2) \
249 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
250 if (s1 && s2) { INFO_CHECK } \
251 s1 = fname_find(sname1); s2 = fname_find(sname2); \
252 if (s1 && s2) { INFO_CHECK } \
253 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
254 if (s1 && s2) { INFO_CHECK } \
258 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
259 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
260 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
261 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
262 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
264 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
268 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
269 VAL_EQUAL(standard_info, size, standard_info, size); \
270 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
271 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
272 VAL_EQUAL(standard_info, directory, standard_info, directory);
274 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
278 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
280 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
284 STR_EQUAL(name_info, fname, name_info, fname);
286 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
290 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
291 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
292 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
293 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
294 VAL_EQUAL(all_info, attrib, all_info, attrib); \
295 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
296 VAL_EQUAL(all_info, size, all_info, size); \
297 VAL_EQUAL(all_info, nlink, all_info, nlink); \
298 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
299 VAL_EQUAL(all_info, directory, all_info, directory); \
300 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
301 STR_EQUAL(all_info, fname, all_info, fname);
303 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
307 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
308 VAL_EQUAL(compression_info, format, compression_info, format); \
309 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
310 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
311 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
313 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
318 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
320 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
323 #define TIME_CHECK_NT(sname, stype, tfield) do { \
324 s1 = fnum_find(sname); \
325 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
326 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
327 nt_time_string(mem_ctx, s1->stype.out.tfield), \
328 nt_time_string(mem_ctx, correct_time)); \
331 s1 = fname_find(sname); \
332 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
333 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
334 nt_time_string(mem_ctx, s1->stype.out.tfield), \
335 nt_time_string(mem_ctx, correct_time)); \
339 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
340 s1 = fnum_find(sname); \
341 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
342 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
343 timestring(mem_ctx, s1->stype.out.tfield), \
344 nt_time_string(mem_ctx, correct_time)); \
347 s1 = fname_find(sname); \
348 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
349 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
350 timestring(mem_ctx, s1->stype.out.tfield), \
351 nt_time_string(mem_ctx, correct_time)); \
355 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
356 s1 = fnum_find(sname); \
357 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
358 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
359 timestring(mem_ctx, s1->stype.out.tfield), \
360 nt_time_string(mem_ctx, correct_time)); \
363 s1 = fname_find(sname); \
364 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
365 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
366 timestring(mem_ctx, s1->stype.out.tfield), \
367 nt_time_string(mem_ctx, correct_time)); \
371 /* now check that all the times that are supposed to be equal are correct */
372 s1 = fnum_find("BASIC_INFO");
373 correct_time = s1->basic_info.out.create_time;
374 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
376 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
377 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
378 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
379 TIME_CHECK_DOS("STANDARD", standard, create_time);
380 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
381 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
382 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
384 s1 = fnum_find("BASIC_INFO");
385 correct_time = s1->basic_info.out.access_time;
386 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
388 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
389 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
390 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
391 TIME_CHECK_DOS("STANDARD", standard, access_time);
392 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
393 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
394 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
396 s1 = fnum_find("BASIC_INFO");
397 correct_time = s1->basic_info.out.write_time;
398 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
400 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
401 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
402 TIME_CHECK_DOS("GETATTR", getattr, write_time);
403 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
404 TIME_CHECK_DOS("STANDARD", standard, write_time);
405 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
406 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
407 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
409 s1 = fnum_find("BASIC_INFO");
410 correct_time = s1->basic_info.out.change_time;
411 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
413 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
414 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
415 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
416 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
419 #define SIZE_CHECK(sname, stype, tfield) do { \
420 s1 = fnum_find(sname); \
421 if (s1 && s1->stype.out.tfield != correct_size) { \
422 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
423 (uint_t)s1->stype.out.tfield, \
424 (uint_t)correct_size); \
427 s1 = fname_find(sname); \
428 if (s1 && s1->stype.out.tfield != correct_size) { \
429 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
430 (uint_t)s1->stype.out.tfield, \
431 (uint_t)correct_size); \
435 s1 = fnum_find("STANDARD_INFO");
436 correct_size = s1->standard_info.out.size;
437 printf("size: %u\n", (uint_t)correct_size);
439 SIZE_CHECK("GETATTR", getattr, size);
440 SIZE_CHECK("GETATTRE", getattre, size);
441 SIZE_CHECK("STANDARD", standard, size);
442 SIZE_CHECK("EA_SIZE", ea_size, size);
443 SIZE_CHECK("STANDARD_INFO", standard_info, size);
444 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
445 SIZE_CHECK("ALL_INFO", all_info, size);
446 SIZE_CHECK("ALL_INFORMATION", all_info, size);
447 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
448 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
449 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
451 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
452 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
456 s1 = fnum_find("STANDARD_INFO");
457 correct_size = s1->standard_info.out.alloc_size;
458 printf("alloc_size: %u\n", (uint_t)correct_size);
460 SIZE_CHECK("GETATTRE", getattre, alloc_size);
461 SIZE_CHECK("STANDARD", standard, alloc_size);
462 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
463 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
464 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
465 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
466 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
467 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
469 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
470 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
473 #define ATTRIB_CHECK(sname, stype, tfield) do { \
474 s1 = fnum_find(sname); \
475 if (s1 && s1->stype.out.tfield != correct_attrib) { \
476 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
477 (uint_t)s1->stype.out.tfield, \
478 (uint_t)correct_attrib); \
481 s1 = fname_find(sname); \
482 if (s1 && s1->stype.out.tfield != correct_attrib) { \
483 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
484 (uint_t)s1->stype.out.tfield, \
485 (uint_t)correct_attrib); \
489 s1 = fnum_find("BASIC_INFO");
490 correct_attrib = s1->basic_info.out.attrib;
491 printf("attrib: 0x%x\n", (uint_t)correct_attrib);
493 ATTRIB_CHECK("GETATTR", getattr, attrib);
494 ATTRIB_CHECK("GETATTRE", getattre, attrib);
495 ATTRIB_CHECK("STANDARD", standard, attrib);
496 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
497 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
498 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
499 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
500 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
501 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
502 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
504 correct_name = fname;
505 printf("name: %s\n", correct_name);
507 #define NAME_CHECK(sname, stype, tfield, flags) do { \
508 s1 = fnum_find(sname); \
509 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
510 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
511 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
512 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
515 s1 = fname_find(sname); \
516 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
517 wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
518 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
519 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
523 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
524 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
526 /* the ALL_INFO file name is the full path on the filesystem */
527 s1 = fnum_find("ALL_INFO");
528 if (s1 && !s1->all_info.out.fname.s) {
529 printf("ALL_INFO didn't give a filename\n");
532 if (s1 && s1->all_info.out.fname.s) {
533 char *p = strrchr(s1->all_info.out.fname.s, '\\');
535 printf("Not a full path in all_info/fname? - '%s'\n",
536 s1->all_info.out.fname.s);
539 if (strcmp_safe(correct_name, p) != 0) {
540 printf("incorrect basename in all_info/fname - '%s'\n",
541 s1->all_info.out.fname.s);
545 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, cli)) {
546 printf("Should not null terminate all_info/fname\n");
551 s1 = fnum_find("ALT_NAME_INFO");
552 correct_name = s1->alt_name_info.out.fname.s;
553 printf("alt_name: %s\n", correct_name);
555 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
556 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
558 /* and make sure we can open by alternate name */
559 smbcli_close(cli->tree, fnum);
560 fnum = smbcli_nt_create_full(cli->tree, correct_name, 0,
562 FILE_ATTRIBUTE_NORMAL,
563 NTCREATEX_SHARE_ACCESS_DELETE|
564 NTCREATEX_SHARE_ACCESS_READ|
565 NTCREATEX_SHARE_ACCESS_WRITE,
566 NTCREATEX_DISP_OVERWRITE_IF,
569 printf("Unable to open by alt_name - %s\n", smbcli_errstr(cli->tree));
574 correct_name = "::$DATA";
575 printf("stream_name: %s\n", correct_name);
577 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
578 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
581 /* make sure the EAs look right */
582 s1 = fnum_find("ALL_EAS");
583 s2 = fnum_find("ALL_INFO");
585 for (i=0;i<s1->all_eas.out.num_eas;i++) {
586 printf(" flags=%d %s=%*.*s\n",
587 s1->all_eas.out.eas[i].flags,
588 s1->all_eas.out.eas[i].name.s,
589 (int)s1->all_eas.out.eas[i].value.length,
590 (int)s1->all_eas.out.eas[i].value.length,
591 s1->all_eas.out.eas[i].value.data);
595 if (s1->all_eas.out.num_eas == 0) {
596 if (s2->all_info.out.ea_size != 0) {
597 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
598 s2->all_info.out.ea_size);
601 if (s2->all_info.out.ea_size !=
602 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
603 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
604 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
605 s2->all_info.out.ea_size);
609 s2 = fname_find("ALL_EAS");
611 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
612 for (i=0;i<s1->all_eas.out.num_eas;i++) {
613 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
614 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
615 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
619 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
620 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
621 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
622 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
623 #stype1, #tfield1, #stype2, #tfield2, \
624 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
627 s1 = fname_find(sname1); s2 = fname_find(sname2); \
628 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
629 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
630 #stype1, #tfield1, #stype2, #tfield2, \
631 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
634 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
635 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
636 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
637 #stype1, #tfield1, #stype2, #tfield2, \
638 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
641 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
642 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
643 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
644 #stype1, #tfield1, #stype2, #tfield2, \
645 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
649 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
650 "ALL_INFO", all_info, delete_pending);
651 VAL_CHECK("STANDARD_INFO", standard_info, directory,
652 "ALL_INFO", all_info, directory);
653 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
654 "ALL_INFO", all_info, nlink);
655 VAL_CHECK("EA_INFO", ea_info, ea_size,
656 "ALL_INFO", all_info, ea_size);
657 VAL_CHECK("EA_SIZE", ea_size, ea_size,
658 "ALL_INFO", all_info, ea_size);
661 #define NAME_PATH_CHECK(sname, stype, field) do { \
662 s1 = fname_find(sname); s2 = fnum_find(sname); \
664 VAL_EQUAL(stype, field, stype, field); \
669 s1 = fnum_find("INTERNAL_INFORMATION");
671 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
674 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
675 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
677 printf("fnum pos = %.0f, fname pos = %.0f\n",
678 (double)s2->position_information.out.position,
679 (double)s1->position_information.out.position );
681 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
682 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
683 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
684 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
687 /* these are expected to differ */
688 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
691 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
692 s1 = fnum_find(sname); \
693 if (s1 && s1->stype.out.tfield != 0) { \
694 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
696 (uint_t)s1->stype.out.tfield); \
698 s1 = fname_find(sname); \
699 if (s1 && s1->stype.out.tfield != 0) { \
700 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
702 (uint_t)s1->stype.out.tfield); \
705 /* now get a bit fancier .... */
707 /* when we set the delete disposition then the link count should drop
708 to 0 and delete_pending should be 1 */
712 smbcli_close(cli->tree, fnum);
713 smbcli_unlink(cli->tree, fname);
715 torture_close_connection(cli);
716 talloc_free(mem_ctx);