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 NTSTATUS fnum_status, fname_status;
29 union smb_fileinfo fnum_finfo, fname_finfo;
31 { "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
32 { "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
33 { "STANDARD", RAW_FILEINFO_STANDARD, },
34 { "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
35 { "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
36 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
37 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
38 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
39 { "EA_INFO", RAW_FILEINFO_EA_INFO, },
40 { "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
41 { "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
42 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
43 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
44 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
45 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
46 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
47 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
48 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
49 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
50 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
51 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
52 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
53 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
54 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
55 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
56 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
57 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
58 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
59 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
64 compare a dos time (2 second resolution) to a nt time
66 static int dos_nt_time_cmp(time_t t, const NTTIME *nt)
68 time_t t2 = nt_time_to_unix(nt);
69 if (ABS(t2 - t) <= 2) return 0;
75 find a level in the levels[] table
77 static union smb_fileinfo *fnum_find(const char *name)
80 for (i=0; levels[i].name; i++) {
81 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
82 strcmp(name, levels[i].name) == 0 &&
83 !levels[i].only_paths) {
84 return &levels[i].fnum_finfo;
91 find a level in the levels[] table
93 static union smb_fileinfo *fname_find(const char *name)
96 for (i=0; levels[i].name; i++) {
97 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
98 strcmp(name, levels[i].name) == 0 &&
99 !levels[i].only_handles) {
100 return &levels[i].fname_finfo;
106 /* local macros to make the code below more readable */
107 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
108 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
109 #n1, #v1, (uint_t)s1->n1.out.v1, \
110 #n2, #v2, (uint_t)s2->n2.out.v2, \
111 __FILE__, __LINE__); \
115 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
116 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
117 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
118 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
119 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
120 __FILE__, __LINE__); \
124 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
125 printf("%s/%s != %s/%s at %s(%d)\n", \
128 __FILE__, __LINE__); \
132 /* used to find hints on unknown values - and to make sure
134 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
135 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
137 (uint_t)s1->n1.out.v1, \
138 (uint_t)s1->n1.out.v1, \
139 __FILE__, __LINE__); \
143 /* basic testing of all RAW_FILEINFO_* calls
144 for each call we test that it succeeds, and where possible test
145 for consistency between the calls.
147 BOOL torture_qfileinfo(int dummy)
149 struct cli_state *cli;
153 union smb_fileinfo *s1, *s2;
156 const char *fname = "\\torture_qfileinfo.txt";
158 large_t correct_size;
159 uint32 correct_attrib;
160 const char *correct_name;
161 BOOL skip_streams = False;
163 if (!torture_open_connection(&cli)) {
167 mem_ctx = talloc_init("torture_qfileinfo");
169 fnum = create_complex_file(cli, mem_ctx, fname);
171 printf("ERROR: open of %s failed (%s)\n", fname, cli_errstr(cli));
177 /* scan all the fileinfo and pathinfo levels */
178 for (i=0; levels[i].name; i++) {
179 if (!levels[i].only_paths) {
180 levels[i].fnum_finfo.generic.level = levels[i].level;
181 levels[i].fnum_finfo.generic.in.fnum = fnum;
182 levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
183 &levels[i].fnum_finfo);
186 if (!levels[i].only_handles) {
187 levels[i].fname_finfo.generic.level = levels[i].level;
188 levels[i].fname_finfo.generic.in.fname = talloc_strdup(mem_ctx, fname);
189 levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
190 &levels[i].fname_finfo);
194 /* check for completely broken levels */
195 for (count=i=0; levels[i].name; i++) {
196 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
197 printf("ERROR: level %s failed - %s\n",
198 levels[i].name, nt_errstr(levels[i].fnum_status));
201 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
202 printf("ERROR: level %s failed - %s\n",
203 levels[i].name, nt_errstr(levels[i].fname_status));
210 printf("%d levels failed\n", count);
212 printf("too many level failures - giving up\n");
217 /* see if we can do streams */
218 s1 = fnum_find("STREAM_INFO");
219 if (!s1 || s1->stream_info.out.num_streams == 0) {
220 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
221 s1 ? s1->stream_info.out.num_streams : -1);
226 /* this code is incredibly repititive but doesn't lend itself to loops, so
227 we use lots of macros to make it less painful */
229 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
230 this code to fail, but we need to check it for completeness */
234 #define ALIAS_CHECK(sname1, sname2) \
236 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
237 if (s1 && s2) { INFO_CHECK } \
238 s1 = fname_find(sname1); s2 = fname_find(sname2); \
239 if (s1 && s2) { INFO_CHECK } \
240 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
241 if (s1 && s2) { INFO_CHECK } \
245 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
246 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
247 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
248 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
249 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
251 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
255 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
256 VAL_EQUAL(standard_info, size, standard_info, size); \
257 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
258 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
259 VAL_EQUAL(standard_info, directory, standard_info, directory);
261 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
265 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
267 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
271 STR_EQUAL(name_info, fname, name_info, fname);
273 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
277 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
278 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
279 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
280 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
281 VAL_EQUAL(all_info, attrib, all_info, attrib); \
282 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
283 VAL_EQUAL(all_info, size, all_info, size); \
284 VAL_EQUAL(all_info, nlink, all_info, nlink); \
285 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
286 VAL_EQUAL(all_info, directory, all_info, directory); \
287 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
288 STR_EQUAL(all_info, fname, all_info, fname);
290 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
295 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
297 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
299 #define TIME_CHECK_NT(sname, stype, tfield) do { \
300 s1 = fnum_find(sname); \
301 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
302 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
303 nt_time_string(mem_ctx, &s1->stype.out.tfield), \
304 nt_time_string(mem_ctx, &correct_time)); \
307 s1 = fname_find(sname); \
308 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
309 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
310 nt_time_string(mem_ctx, &s1->stype.out.tfield), \
311 nt_time_string(mem_ctx, &correct_time)); \
315 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
316 s1 = fnum_find(sname); \
317 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
318 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
319 time_string(mem_ctx, s1->stype.out.tfield), \
320 nt_time_string(mem_ctx, &correct_time)); \
323 s1 = fname_find(sname); \
324 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
325 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
326 time_string(mem_ctx, s1->stype.out.tfield), \
327 nt_time_string(mem_ctx, &correct_time)); \
331 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
332 s1 = fnum_find(sname); \
333 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
334 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
335 time_string(mem_ctx, s1->stype.out.tfield), \
336 nt_time_string(mem_ctx, &correct_time)); \
339 s1 = fname_find(sname); \
340 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, &correct_time) != 0) { \
341 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
342 time_string(mem_ctx, s1->stype.out.tfield), \
343 nt_time_string(mem_ctx, &correct_time)); \
347 /* now check that all the times that are supposed to be equal are correct */
348 s1 = fnum_find("BASIC_INFO");
349 correct_time = s1->basic_info.out.create_time;
350 printf("create_time: %s\n", nt_time_string(mem_ctx, &correct_time));
352 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
353 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
354 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
355 TIME_CHECK_DOS("STANDARD", standard, create_time);
356 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
357 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
358 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
360 s1 = fnum_find("BASIC_INFO");
361 correct_time = s1->basic_info.out.access_time;
362 printf("access_time: %s\n", nt_time_string(mem_ctx, &correct_time));
364 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
365 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
366 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
367 TIME_CHECK_DOS("STANDARD", standard, access_time);
368 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
369 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
370 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
372 s1 = fnum_find("BASIC_INFO");
373 correct_time = s1->basic_info.out.write_time;
374 printf("write_time : %s\n", nt_time_string(mem_ctx, &correct_time));
376 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
377 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
378 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
379 TIME_CHECK_DOS("STANDARD", standard, write_time);
380 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
381 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
382 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
384 s1 = fnum_find("BASIC_INFO");
385 correct_time = s1->basic_info.out.change_time;
386 printf("change_time: %s\n", nt_time_string(mem_ctx, &correct_time));
388 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
389 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
390 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
391 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
394 #define SIZE_CHECK(sname, stype, tfield) do { \
395 s1 = fnum_find(sname); \
396 if (s1 && s1->stype.out.tfield != correct_size) { \
397 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
398 (unsigned)s1->stype.out.tfield, \
399 (unsigned)correct_size); \
402 s1 = fname_find(sname); \
403 if (s1 && s1->stype.out.tfield != correct_size) { \
404 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
405 (unsigned)s1->stype.out.tfield, \
406 (unsigned)correct_size); \
410 s1 = fnum_find("STANDARD_INFO");
411 correct_size = s1->standard_info.out.size;
412 printf("size: %u\n", (unsigned)correct_size);
414 SIZE_CHECK("GETATTR", getattr, size);
415 SIZE_CHECK("GETATTRE", getattre, size);
416 SIZE_CHECK("STANDARD", standard, size);
417 SIZE_CHECK("EA_SIZE", ea_size, size);
418 SIZE_CHECK("STANDARD_INFO", standard_info, size);
419 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
420 SIZE_CHECK("ALL_INFO", all_info, size);
421 SIZE_CHECK("ALL_INFORMATION", all_info, size);
422 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
423 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
424 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
426 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
427 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
431 s1 = fnum_find("STANDARD_INFO");
432 correct_size = s1->standard_info.out.alloc_size;
433 printf("alloc_size: %u\n", (unsigned)correct_size);
435 SIZE_CHECK("GETATTRE", getattre, alloc_size);
436 SIZE_CHECK("STANDARD", standard, alloc_size);
437 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
438 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
439 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
440 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
441 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
442 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
444 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
445 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
448 #define ATTRIB_CHECK(sname, stype, tfield) do { \
449 s1 = fnum_find(sname); \
450 if (s1 && s1->stype.out.tfield != correct_attrib) { \
451 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
452 (unsigned)s1->stype.out.tfield, \
453 (unsigned)correct_attrib); \
456 s1 = fname_find(sname); \
457 if (s1 && s1->stype.out.tfield != correct_attrib) { \
458 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
459 (unsigned)s1->stype.out.tfield, \
460 (unsigned)correct_attrib); \
464 s1 = fnum_find("BASIC_INFO");
465 correct_attrib = s1->basic_info.out.attrib;
466 printf("attrib: 0x%x\n", (unsigned)correct_attrib);
468 ATTRIB_CHECK("GETATTR", getattr, attrib);
469 ATTRIB_CHECK("GETATTRE", getattre, attrib);
470 ATTRIB_CHECK("STANDARD", standard, attrib);
471 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
472 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
473 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
474 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
475 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
476 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
477 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
479 correct_name = fname;
480 printf("name: %s\n", correct_name);
482 #define NAME_CHECK(sname, stype, tfield, flags) do { \
483 s1 = fnum_find(sname); \
484 if ((s1 && strcmp(s1->stype.out.tfield.s, correct_name) != 0) || \
485 wire_bad_flags(&s1->stype.out.tfield, flags)) { \
486 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
487 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
490 s1 = fname_find(sname); \
491 if ((s1 && strcmp(s1->stype.out.tfield.s, correct_name)) != 0 || \
492 wire_bad_flags(&s1->stype.out.tfield, flags)) { \
493 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
494 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
498 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
499 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
501 /* the ALL_INFO file name is the full path on the filesystem */
502 s1 = fnum_find("ALL_INFO");
503 if (s1 && !s1->all_info.out.fname.s) {
504 printf("ALL_INFO didn't give a filename\n");
507 if (s1 && s1->all_info.out.fname.s) {
508 char *p = strrchr(s1->all_info.out.fname.s, '\\');
510 printf("Not a full path in all_info/fname? - '%s'\n",
511 s1->all_info.out.fname.s);
514 if (strcmp(correct_name, p) != 0) {
515 printf("incorrect basename in all_info/fname - '%s'\n",
516 s1->all_info.out.fname.s);
520 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE)) {
521 printf("Should not null terminate all_info/fname\n");
526 s1 = fnum_find("ALT_NAME_INFO");
527 correct_name = s1->alt_name_info.out.fname.s;
528 printf("alt_name: %s\n", correct_name);
530 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
531 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
533 /* and make sure we can open by alternate name */
534 cli_close(cli, fnum);
535 fnum = cli_nt_create_full(cli, correct_name, 0, NT_ACCESS_GENERIC_ALL_ACCESS,
536 FILE_ATTRIBUTE_NORMAL,
537 NTCREATEX_SHARE_ACCESS_DELETE|
538 NTCREATEX_SHARE_ACCESS_READ|
539 NTCREATEX_SHARE_ACCESS_WRITE,
543 printf("Unable to open by alt_name - %s\n", cli_errstr(cli));
548 correct_name = "::$DATA";
549 printf("stream_name: %s\n", correct_name);
551 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
552 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
555 /* make sure the EAs look right */
556 s1 = fnum_find("ALL_EAS");
558 printf("ea_size: %d\n", s1->all_eas.out.ea_size);
559 for (i=0;i<s1->all_eas.out.num_eas;i++) {
560 printf(" flags=%d %s=%*.*s\n",
561 s1->all_eas.out.eas[i].flags,
562 s1->all_eas.out.eas[i].name.s,
563 s1->all_eas.out.eas[i].value.length,
564 s1->all_eas.out.eas[i].value.length,
565 s1->all_eas.out.eas[i].value.data);
570 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
571 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
572 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
573 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
574 #stype1, #tfield1, #stype2, #tfield2, \
575 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
578 s1 = fname_find(sname1); s2 = fname_find(sname2); \
579 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
580 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
581 #stype1, #tfield1, #stype2, #tfield2, \
582 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
585 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
586 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
587 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
588 #stype1, #tfield1, #stype2, #tfield2, \
589 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
592 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
593 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
594 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
595 #stype1, #tfield1, #stype2, #tfield2, \
596 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
600 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
601 "ALL_INFO", all_info, delete_pending);
602 VAL_CHECK("STANDARD_INFO", standard_info, directory,
603 "ALL_INFO", all_info, directory);
604 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
605 "ALL_INFO", all_info, nlink);
606 VAL_CHECK("EA_INFO", ea_info, ea_size,
607 "ALL_INFO", all_info, ea_size);
608 VAL_CHECK("ALL_EAS", all_eas, ea_size,
609 "ALL_INFO", all_info, ea_size);
610 VAL_CHECK("EA_SIZE", ea_size, ea_size,
611 "ALL_INFO", all_info, ea_size);
613 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
614 s1 = fnum_find(sname); \
615 if (s1 && s1->stype.out.tfield != 0) { \
616 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
618 (unsigned)s1->stype.out.tfield); \
620 s1 = fname_find(sname); \
621 if (s1 && s1->stype.out.tfield != 0) { \
622 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
624 (unsigned)s1->stype.out.tfield); \
627 /* now get a bit fancier .... */
629 /* when we set the delete disposition then the link count should drop
630 to 0 and delete_pending should be 1 */
634 cli_close(cli, fnum);
635 cli_unlink(cli, fname);
637 torture_close_connection(cli);
638 talloc_destroy(mem_ctx);