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.
25 enum fileinfo_level level;
26 unsigned only_paths:1;
27 unsigned only_handles:1;
28 uint32 capability_mask;
29 NTSTATUS fnum_status, fname_status;
30 union smb_fileinfo fnum_finfo, fname_finfo;
32 { "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
33 { "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
34 { "STANDARD", RAW_FILEINFO_STANDARD, },
35 { "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
36 { "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
37 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
38 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
39 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
40 { "EA_INFO", RAW_FILEINFO_EA_INFO, },
41 { "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
42 { "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
43 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
44 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
45 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
46 { "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
47 { "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
48 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
49 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
50 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
51 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
52 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
53 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
54 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
55 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
56 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
57 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
58 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
59 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
60 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
61 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
62 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
67 compare a dos time (2 second resolution) to a nt time
69 static int dos_nt_time_cmp(time_t t, NTTIME nt)
71 time_t t2 = nt_time_to_unix(nt);
72 if (ABS(t2 - t) <= 2) return 0;
78 find a level in the levels[] table
80 static union smb_fileinfo *fnum_find(const char *name)
83 for (i=0; levels[i].name; i++) {
84 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
85 strcmp(name, levels[i].name) == 0 &&
86 !levels[i].only_paths) {
87 return &levels[i].fnum_finfo;
94 find a level in the levels[] table
96 static union smb_fileinfo *fname_find(const char *name)
99 for (i=0; levels[i].name; i++) {
100 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
101 strcmp(name, levels[i].name) == 0 &&
102 !levels[i].only_handles) {
103 return &levels[i].fname_finfo;
109 /* local macros to make the code below more readable */
110 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
111 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
112 #n1, #v1, (uint_t)s1->n1.out.v1, \
113 #n2, #v2, (uint_t)s2->n2.out.v2, \
114 __FILE__, __LINE__); \
118 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
119 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
120 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
121 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
122 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
123 __FILE__, __LINE__); \
127 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
128 printf("%s/%s != %s/%s at %s(%d)\n", \
131 __FILE__, __LINE__); \
135 /* used to find hints on unknown values - and to make sure
137 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
138 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
140 (uint_t)s1->n1.out.v1, \
141 (uint_t)s1->n1.out.v1, \
142 __FILE__, __LINE__); \
146 /* basic testing of all RAW_FILEINFO_* calls
147 for each call we test that it succeeds, and where possible test
148 for consistency between the calls.
150 BOOL torture_raw_qfileinfo(int dummy)
152 struct cli_state *cli;
156 union smb_fileinfo *s1, *s2;
159 const char *fname = "\\torture_qfileinfo.txt";
161 uint64_t correct_size;
162 uint32 correct_attrib;
163 const char *correct_name;
164 BOOL skip_streams = False;
166 if (!torture_open_connection(&cli)) {
170 mem_ctx = talloc_init("torture_qfileinfo");
172 fnum = create_complex_file(cli, mem_ctx, fname);
174 printf("ERROR: open of %s failed (%s)\n", fname, cli_errstr(cli->tree));
180 /* scan all the fileinfo and pathinfo levels */
181 for (i=0; levels[i].name; i++) {
182 if (!levels[i].only_paths) {
183 levels[i].fnum_finfo.generic.level = levels[i].level;
184 levels[i].fnum_finfo.generic.in.fnum = fnum;
185 levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
186 &levels[i].fnum_finfo);
189 if (!levels[i].only_handles) {
190 levels[i].fname_finfo.generic.level = levels[i].level;
191 levels[i].fname_finfo.generic.in.fname = talloc_strdup(mem_ctx, fname);
192 levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
193 &levels[i].fname_finfo);
197 /* check for completely broken levels */
198 for (count=i=0; levels[i].name; i++) {
199 uint32 cap = cli->transport->negotiate.capabilities;
200 /* see if this server claims to support this level */
201 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
205 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
206 printf("ERROR: level %s failed - %s\n",
207 levels[i].name, nt_errstr(levels[i].fnum_status));
210 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
211 printf("ERROR: level %s failed - %s\n",
212 levels[i].name, nt_errstr(levels[i].fname_status));
219 printf("%d levels failed\n", count);
221 printf("too many level failures - giving up\n");
226 /* see if we can do streams */
227 s1 = fnum_find("STREAM_INFO");
228 if (!s1 || s1->stream_info.out.num_streams == 0) {
229 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
230 s1 ? s1->stream_info.out.num_streams : -1);
235 /* this code is incredibly repititive but doesn't lend itself to loops, so
236 we use lots of macros to make it less painful */
238 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
239 this code to fail, but we need to check it for completeness */
243 #define ALIAS_CHECK(sname1, sname2) \
245 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
246 if (s1 && s2) { INFO_CHECK } \
247 s1 = fname_find(sname1); s2 = fname_find(sname2); \
248 if (s1 && s2) { INFO_CHECK } \
249 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
250 if (s1 && s2) { INFO_CHECK } \
254 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
255 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
256 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
257 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
258 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
260 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
264 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
265 VAL_EQUAL(standard_info, size, standard_info, size); \
266 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
267 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
268 VAL_EQUAL(standard_info, directory, standard_info, directory);
270 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
274 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
276 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
280 STR_EQUAL(name_info, fname, name_info, fname);
282 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
286 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
287 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
288 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
289 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
290 VAL_EQUAL(all_info, attrib, all_info, attrib); \
291 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
292 VAL_EQUAL(all_info, size, all_info, size); \
293 VAL_EQUAL(all_info, nlink, all_info, nlink); \
294 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
295 VAL_EQUAL(all_info, directory, all_info, directory); \
296 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
297 STR_EQUAL(all_info, fname, all_info, fname);
299 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
303 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
304 VAL_EQUAL(compression_info, format, compression_info, format); \
305 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
306 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
307 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
309 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
314 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
316 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
319 #define TIME_CHECK_NT(sname, stype, tfield) do { \
320 s1 = fnum_find(sname); \
321 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
322 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
323 nt_time_string(mem_ctx, s1->stype.out.tfield), \
324 nt_time_string(mem_ctx, correct_time)); \
327 s1 = fname_find(sname); \
328 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
329 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
330 nt_time_string(mem_ctx, s1->stype.out.tfield), \
331 nt_time_string(mem_ctx, correct_time)); \
335 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
336 s1 = fnum_find(sname); \
337 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
338 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
339 timestring(mem_ctx, s1->stype.out.tfield), \
340 nt_time_string(mem_ctx, correct_time)); \
343 s1 = fname_find(sname); \
344 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
345 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
346 timestring(mem_ctx, s1->stype.out.tfield), \
347 nt_time_string(mem_ctx, correct_time)); \
351 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
352 s1 = fnum_find(sname); \
353 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
354 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
355 timestring(mem_ctx, s1->stype.out.tfield), \
356 nt_time_string(mem_ctx, correct_time)); \
359 s1 = fname_find(sname); \
360 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
361 printf("(%d) path %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)); \
367 /* now check that all the times that are supposed to be equal are correct */
368 s1 = fnum_find("BASIC_INFO");
369 correct_time = s1->basic_info.out.create_time;
370 printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
372 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
373 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
374 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
375 TIME_CHECK_DOS("STANDARD", standard, create_time);
376 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
377 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
378 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
380 s1 = fnum_find("BASIC_INFO");
381 correct_time = s1->basic_info.out.access_time;
382 printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
384 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
385 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
386 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
387 TIME_CHECK_DOS("STANDARD", standard, access_time);
388 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
389 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
390 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
392 s1 = fnum_find("BASIC_INFO");
393 correct_time = s1->basic_info.out.write_time;
394 printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
396 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
397 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
398 TIME_CHECK_DOS("GETATTR", getattr, write_time);
399 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
400 TIME_CHECK_DOS("STANDARD", standard, write_time);
401 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
402 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
403 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
405 s1 = fnum_find("BASIC_INFO");
406 correct_time = s1->basic_info.out.change_time;
407 printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
409 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
410 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
411 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
412 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
415 #define SIZE_CHECK(sname, stype, tfield) do { \
416 s1 = fnum_find(sname); \
417 if (s1 && s1->stype.out.tfield != correct_size) { \
418 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
419 (unsigned)s1->stype.out.tfield, \
420 (unsigned)correct_size); \
423 s1 = fname_find(sname); \
424 if (s1 && s1->stype.out.tfield != correct_size) { \
425 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
426 (unsigned)s1->stype.out.tfield, \
427 (unsigned)correct_size); \
431 s1 = fnum_find("STANDARD_INFO");
432 correct_size = s1->standard_info.out.size;
433 printf("size: %u\n", (unsigned)correct_size);
435 SIZE_CHECK("GETATTR", getattr, size);
436 SIZE_CHECK("GETATTRE", getattre, size);
437 SIZE_CHECK("STANDARD", standard, size);
438 SIZE_CHECK("EA_SIZE", ea_size, size);
439 SIZE_CHECK("STANDARD_INFO", standard_info, size);
440 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
441 SIZE_CHECK("ALL_INFO", all_info, size);
442 SIZE_CHECK("ALL_INFORMATION", all_info, size);
443 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
444 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
445 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
447 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
448 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
452 s1 = fnum_find("STANDARD_INFO");
453 correct_size = s1->standard_info.out.alloc_size;
454 printf("alloc_size: %u\n", (unsigned)correct_size);
456 SIZE_CHECK("GETATTRE", getattre, alloc_size);
457 SIZE_CHECK("STANDARD", standard, alloc_size);
458 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
459 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
460 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
461 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
462 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
463 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
465 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
466 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
469 #define ATTRIB_CHECK(sname, stype, tfield) do { \
470 s1 = fnum_find(sname); \
471 if (s1 && s1->stype.out.tfield != correct_attrib) { \
472 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
473 (unsigned)s1->stype.out.tfield, \
474 (unsigned)correct_attrib); \
477 s1 = fname_find(sname); \
478 if (s1 && s1->stype.out.tfield != correct_attrib) { \
479 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
480 (unsigned)s1->stype.out.tfield, \
481 (unsigned)correct_attrib); \
485 s1 = fnum_find("BASIC_INFO");
486 correct_attrib = s1->basic_info.out.attrib;
487 printf("attrib: 0x%x\n", (unsigned)correct_attrib);
489 ATTRIB_CHECK("GETATTR", getattr, attrib);
490 ATTRIB_CHECK("GETATTRE", getattre, attrib);
491 ATTRIB_CHECK("STANDARD", standard, attrib);
492 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
493 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
494 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
495 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
496 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
497 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
498 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
500 correct_name = fname;
501 printf("name: %s\n", correct_name);
503 #define NAME_CHECK(sname, stype, tfield, flags) do { \
504 s1 = fnum_find(sname); \
505 if (s1 && (strcmp(s1->stype.out.tfield.s, correct_name) != 0 || \
506 wire_bad_flags(&s1->stype.out.tfield, flags))) { \
507 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
508 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
511 s1 = fname_find(sname); \
512 if (s1 && (strcmp(s1->stype.out.tfield.s, correct_name) != 0 || \
513 wire_bad_flags(&s1->stype.out.tfield, flags))) { \
514 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
515 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
519 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
520 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
522 /* the ALL_INFO file name is the full path on the filesystem */
523 s1 = fnum_find("ALL_INFO");
524 if (s1 && !s1->all_info.out.fname.s) {
525 printf("ALL_INFO didn't give a filename\n");
528 if (s1 && s1->all_info.out.fname.s) {
529 char *p = strrchr(s1->all_info.out.fname.s, '\\');
531 printf("Not a full path in all_info/fname? - '%s'\n",
532 s1->all_info.out.fname.s);
535 if (strcmp(correct_name, p) != 0) {
536 printf("incorrect basename in all_info/fname - '%s'\n",
537 s1->all_info.out.fname.s);
541 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE)) {
542 printf("Should not null terminate all_info/fname\n");
547 s1 = fnum_find("ALT_NAME_INFO");
548 correct_name = s1->alt_name_info.out.fname.s;
549 printf("alt_name: %s\n", correct_name);
551 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
552 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
554 /* and make sure we can open by alternate name */
555 cli_close(cli->tree, fnum);
556 fnum = cli_nt_create_full(cli->tree, correct_name, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
557 FILE_ATTRIBUTE_NORMAL,
558 NTCREATEX_SHARE_ACCESS_DELETE|
559 NTCREATEX_SHARE_ACCESS_READ|
560 NTCREATEX_SHARE_ACCESS_WRITE,
561 NTCREATEX_DISP_OVERWRITE_IF,
564 printf("Unable to open by alt_name - %s\n", cli_errstr(cli->tree));
569 correct_name = "::$DATA";
570 printf("stream_name: %s\n", correct_name);
572 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
573 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
576 /* make sure the EAs look right */
577 s1 = fnum_find("ALL_EAS");
578 s2 = fnum_find("ALL_INFO");
580 for (i=0;i<s1->all_eas.out.num_eas;i++) {
581 printf(" flags=%d %s=%*.*s\n",
582 s1->all_eas.out.eas[i].flags,
583 s1->all_eas.out.eas[i].name.s,
584 s1->all_eas.out.eas[i].value.length,
585 s1->all_eas.out.eas[i].value.length,
586 s1->all_eas.out.eas[i].value.data);
590 if (s1->all_eas.out.num_eas == 0) {
591 if (s2->all_info.out.ea_size != 0) {
592 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
593 s2->all_info.out.ea_size);
596 if (s2->all_info.out.ea_size !=
597 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
598 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
599 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
600 s2->all_info.out.ea_size);
604 s2 = fname_find("ALL_EAS");
606 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
607 for (i=0;i<s1->all_eas.out.num_eas;i++) {
608 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
609 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
610 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
614 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
615 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
616 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
617 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
618 #stype1, #tfield1, #stype2, #tfield2, \
619 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
622 s1 = fname_find(sname1); s2 = fname_find(sname2); \
623 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
624 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
625 #stype1, #tfield1, #stype2, #tfield2, \
626 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
629 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
630 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
631 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
632 #stype1, #tfield1, #stype2, #tfield2, \
633 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
636 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
637 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
638 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
639 #stype1, #tfield1, #stype2, #tfield2, \
640 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
644 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
645 "ALL_INFO", all_info, delete_pending);
646 VAL_CHECK("STANDARD_INFO", standard_info, directory,
647 "ALL_INFO", all_info, directory);
648 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
649 "ALL_INFO", all_info, nlink);
650 VAL_CHECK("EA_INFO", ea_info, ea_size,
651 "ALL_INFO", all_info, ea_size);
652 VAL_CHECK("EA_SIZE", ea_size, ea_size,
653 "ALL_INFO", all_info, ea_size);
656 #define NAME_PATH_CHECK(sname, stype, field) do { \
657 s1 = fname_find(sname); s2 = fnum_find(sname); \
659 VAL_EQUAL(stype, field, stype, field); \
664 s1 = fnum_find("INTERNAL_INFORMATION");
666 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
669 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
670 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
672 printf("fnum pos = %.0f, fname pos = %.0f\n",
673 (double)s2->position_information.out.position,
674 (double)s1->position_information.out.position );
676 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
677 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
678 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
679 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
682 /* these are expected to differ */
683 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
686 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
687 s1 = fnum_find(sname); \
688 if (s1 && s1->stype.out.tfield != 0) { \
689 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
691 (unsigned)s1->stype.out.tfield); \
693 s1 = fname_find(sname); \
694 if (s1 && s1->stype.out.tfield != 0) { \
695 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
697 (unsigned)s1->stype.out.tfield); \
700 /* now get a bit fancier .... */
702 /* when we set the delete disposition then the link count should drop
703 to 0 and delete_pending should be 1 */
707 cli_close(cli->tree, fnum);
708 cli_unlink(cli->tree, fname);
710 torture_close_connection(cli);
711 talloc_destroy(mem_ctx);