r22838: Add in an explority test for what QFSINFO operations are valid on IPC$
[Samba.git] / source / torture / raw / qfileinfo.c
blobfad32f6a9eee56770b295c3102b9b6714d55dc76
1 /*
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.
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "torture/rpc/rpc.h"
29 static struct {
30 const char *name;
31 enum smb_fileinfo_level level;
32 uint_t only_paths:1;
33 uint_t only_handles:1;
34 uint32_t capability_mask;
35 NTSTATUS fnum_status, fname_status;
36 union smb_fileinfo fnum_finfo, fname_finfo;
37 } levels[] = {
38 { "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
39 { "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
40 { "STANDARD", RAW_FILEINFO_STANDARD, },
41 { "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
42 { "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
43 { "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
44 { "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
45 { "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
46 { "EA_INFO", RAW_FILEINFO_EA_INFO, },
47 { "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
48 { "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
49 { "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
50 { "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
51 { "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
52 { "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
53 { "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
54 { "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
55 { "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
56 { "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
57 { "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
58 { "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
59 { "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
60 { "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
61 { "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
62 { "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
63 { "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
64 { "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
65 { "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
66 { "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
67 { "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
68 { "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
69 { NULL, }
72 static bool is_ipc;
75 compare a dos time (2 second resolution) to a nt time
77 static int dos_nt_time_cmp(time_t t, NTTIME nt)
79 time_t t2 = nt_time_to_unix(nt);
80 if (abs(t2 - t) <= 2) return 0;
81 return t2 - t;
86 find a level in the levels[] table
88 static union smb_fileinfo *fnum_find(const char *name)
90 int i;
91 for (i=0; levels[i].name; i++) {
92 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
93 strcmp(name, levels[i].name) == 0 &&
94 !levels[i].only_paths) {
95 return &levels[i].fnum_finfo;
98 return NULL;
102 find a level in the levels[] table
104 static union smb_fileinfo *fname_find(const char *name)
106 int i;
107 if (is_ipc) {
108 return NULL;
110 for (i=0; levels[i].name; i++) {
111 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
112 strcmp(name, levels[i].name) == 0 &&
113 !levels[i].only_handles) {
114 return &levels[i].fname_finfo;
117 return NULL;
120 /* local macros to make the code below more readable */
121 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
122 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
123 #n1, #v1, (uint_t)s1->n1.out.v1, \
124 #n2, #v2, (uint_t)s2->n2.out.v2, \
125 __FILE__, __LINE__); \
126 ret = False; \
127 }} while(0)
129 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
130 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
131 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
132 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
133 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
134 __FILE__, __LINE__); \
135 ret = False; \
136 }} while(0)
138 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
139 printf("%s/%s != %s/%s at %s(%d)\n", \
140 #n1, #v1, \
141 #n2, #v2, \
142 __FILE__, __LINE__); \
143 ret = False; \
144 }} while(0)
146 /* used to find hints on unknown values - and to make sure
147 we zero-fill */
148 #if 0 /* unused */
149 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
150 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
151 #n1, #v1, \
152 (uint_t)s1->n1.out.v1, \
153 (uint_t)s1->n1.out.v1, \
154 __FILE__, __LINE__); \
155 ret = False; \
156 }} while(0)
157 #endif
159 /* basic testing of all RAW_FILEINFO_* calls
160 for each call we test that it succeeds, and where possible test
161 for consistency between the calls.
163 static BOOL torture_raw_qfileinfo_internals(struct torture_context *torture, TALLOC_CTX *mem_ctx,
164 struct smbcli_tree *tree, int fnum, const char *fname)
166 int i;
167 BOOL ret = True;
168 int count;
169 union smb_fileinfo *s1, *s2;
170 NTTIME correct_time;
171 uint64_t correct_size;
172 uint32_t correct_attrib;
173 const char *correct_name;
174 BOOL skip_streams = False;
176 /* scan all the fileinfo and pathinfo levels */
177 for (i=0; levels[i].name; i++) {
178 if (!levels[i].only_paths) {
179 levels[i].fnum_finfo.generic.level = levels[i].level;
180 levels[i].fnum_finfo.generic.in.file.fnum = fnum;
181 levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx,
182 &levels[i].fnum_finfo);
185 if (!levels[i].only_handles) {
186 levels[i].fname_finfo.generic.level = levels[i].level;
187 levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
188 levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx,
189 &levels[i].fname_finfo);
193 /* check for completely broken levels */
194 for (count=i=0; levels[i].name; i++) {
195 uint32_t cap = tree->session->transport->negotiate.capabilities;
196 /* see if this server claims to support this level */
197 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
198 continue;
201 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
202 printf("ERROR: level %s failed - %s\n",
203 levels[i].name, nt_errstr(levels[i].fnum_status));
204 count++;
206 if (!(is_ipc || levels[i].only_handles) && !NT_STATUS_IS_OK(levels[i].fname_status)) {
207 printf("ERROR: level %s failed - %s\n",
208 levels[i].name, nt_errstr(levels[i].fname_status));
209 count++;
213 if (count != 0) {
214 ret = False;
215 printf("%d levels failed\n", count);
216 if (count > 35) {
217 printf("too many level failures - giving up\n");
218 goto done;
222 /* see if we can do streams */
223 s1 = fnum_find("STREAM_INFO");
224 if (!s1 || s1->stream_info.out.num_streams == 0) {
225 if (!is_ipc) {
226 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
227 s1 ? s1->stream_info.out.num_streams : -1);
229 skip_streams = True;
233 /* this code is incredibly repititive but doesn't lend itself to loops, so
234 we use lots of macros to make it less painful */
236 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
237 this code to fail, but we need to check it for completeness */
241 #define ALIAS_CHECK(sname1, sname2) \
242 do { \
243 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
244 if (s1 && s2) { INFO_CHECK } \
245 s1 = fname_find(sname1); s2 = fname_find(sname2); \
246 if (s1 && s2) { INFO_CHECK } \
247 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
248 if (s1 && s2) { INFO_CHECK } \
249 } while (0)
251 #define INFO_CHECK \
252 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
253 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
254 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
255 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
256 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
258 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
260 #undef INFO_CHECK
261 #define INFO_CHECK \
262 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
263 VAL_EQUAL(standard_info, size, standard_info, size); \
264 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
265 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
266 VAL_EQUAL(standard_info, directory, standard_info, directory);
268 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
270 #undef INFO_CHECK
271 #define INFO_CHECK \
272 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
274 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
276 #undef INFO_CHECK
277 #define INFO_CHECK \
278 STR_EQUAL(name_info, fname, name_info, fname);
280 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
282 #undef INFO_CHECK
283 #define INFO_CHECK \
284 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
285 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
286 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
287 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
288 VAL_EQUAL(all_info, attrib, all_info, attrib); \
289 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
290 VAL_EQUAL(all_info, size, all_info, size); \
291 VAL_EQUAL(all_info, nlink, all_info, nlink); \
292 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
293 VAL_EQUAL(all_info, directory, all_info, directory); \
294 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
295 STR_EQUAL(all_info, fname, all_info, fname);
297 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
299 #undef INFO_CHECK
300 #define INFO_CHECK \
301 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
302 VAL_EQUAL(compression_info, format, compression_info, format); \
303 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
304 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
305 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
307 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
310 #undef INFO_CHECK
311 #define INFO_CHECK \
312 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
314 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
317 #define TIME_CHECK_NT(sname, stype, tfield) do { \
318 s1 = fnum_find(sname); \
319 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
320 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
321 nt_time_string(mem_ctx, s1->stype.out.tfield), \
322 nt_time_string(mem_ctx, correct_time)); \
323 ret = False; \
325 s1 = fname_find(sname); \
326 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
327 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
328 nt_time_string(mem_ctx, s1->stype.out.tfield), \
329 nt_time_string(mem_ctx, correct_time)); \
330 ret = False; \
331 }} while (0)
333 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
334 s1 = fnum_find(sname); \
335 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
336 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
337 timestring(mem_ctx, s1->stype.out.tfield), \
338 nt_time_string(mem_ctx, correct_time)); \
339 ret = False; \
341 s1 = fname_find(sname); \
342 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
343 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
344 timestring(mem_ctx, s1->stype.out.tfield), \
345 nt_time_string(mem_ctx, correct_time)); \
346 ret = False; \
347 }} while (0)
349 #if 0 /* unused */
350 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
351 s1 = fnum_find(sname); \
352 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
353 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
354 timestring(mem_ctx, s1->stype.out.tfield), \
355 nt_time_string(mem_ctx, correct_time)); \
356 ret = False; \
358 s1 = fname_find(sname); \
359 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
360 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
361 timestring(mem_ctx, s1->stype.out.tfield), \
362 nt_time_string(mem_ctx, correct_time)); \
363 ret = False; \
364 }} while (0)
365 #endif
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 (uint_t)s1->stype.out.tfield, \
420 (uint_t)correct_size); \
421 ret = False; \
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 (uint_t)s1->stype.out.tfield, \
427 (uint_t)correct_size); \
428 ret = False; \
429 }} while (0)
431 s1 = fnum_find("STANDARD_INFO");
432 correct_size = s1->standard_info.out.size;
433 printf("size: %u\n", (uint_t)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);
446 if (!skip_streams) {
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", (uint_t)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);
464 if (!skip_streams) {
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 (uint_t)s1->stype.out.tfield, \
474 (uint_t)correct_attrib); \
475 ret = False; \
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 (uint_t)s1->stype.out.tfield, \
481 (uint_t)correct_attrib); \
482 ret = False; \
483 }} while (0)
485 s1 = fnum_find("BASIC_INFO");
486 correct_attrib = s1->basic_info.out.attrib;
487 printf("attrib: 0x%x\n", (uint_t)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_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
506 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
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); \
509 ret = False; \
511 s1 = fname_find(sname); \
512 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
513 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
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); \
516 ret = False; \
517 }} while (0)
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");
526 ret = False;
528 if (s1 && s1->all_info.out.fname.s) {
529 char *p = strrchr(s1->all_info.out.fname.s, '\\');
530 if (!p) {
531 printf("Not a full path in all_info/fname? - '%s'\n",
532 s1->all_info.out.fname.s);
533 ret = False;
534 } else {
535 if (strcmp_safe(correct_name, p) != 0) {
536 printf("incorrect basename in all_info/fname - '%s'\n",
537 s1->all_info.out.fname.s);
538 ret = False;
541 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
542 printf("Should not null terminate all_info/fname\n");
543 ret = False;
547 s1 = fnum_find("ALT_NAME_INFO");
548 if (s1) {
549 correct_name = s1->alt_name_info.out.fname.s;
550 printf("alt_name: %s\n", correct_name);
552 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
553 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
555 /* and make sure we can open by alternate name */
556 smbcli_close(tree, fnum);
557 fnum = smbcli_nt_create_full(tree, correct_name, 0,
558 SEC_RIGHTS_FILE_ALL,
559 FILE_ATTRIBUTE_NORMAL,
560 NTCREATEX_SHARE_ACCESS_DELETE|
561 NTCREATEX_SHARE_ACCESS_READ|
562 NTCREATEX_SHARE_ACCESS_WRITE,
563 NTCREATEX_DISP_OVERWRITE_IF,
564 0, 0);
565 if (fnum == -1) {
566 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
567 ret = False;
570 if (!skip_streams) {
571 correct_name = "::$DATA";
572 printf("stream_name: %s\n", correct_name);
574 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
575 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
579 /* make sure the EAs look right */
580 s1 = fnum_find("ALL_EAS");
581 s2 = fnum_find("ALL_INFO");
582 if (s1) {
583 for (i=0;i<s1->all_eas.out.num_eas;i++) {
584 printf(" flags=%d %s=%*.*s\n",
585 s1->all_eas.out.eas[i].flags,
586 s1->all_eas.out.eas[i].name.s,
587 (int)s1->all_eas.out.eas[i].value.length,
588 (int)s1->all_eas.out.eas[i].value.length,
589 s1->all_eas.out.eas[i].value.data);
592 if (s1 && s2) {
593 if (s1->all_eas.out.num_eas == 0) {
594 if (s2->all_info.out.ea_size != 0) {
595 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
596 s2->all_info.out.ea_size);
598 } else {
599 if (s2->all_info.out.ea_size !=
600 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
601 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
602 (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
603 (int)s2->all_info.out.ea_size);
607 s2 = fname_find("ALL_EAS");
608 if (s2) {
609 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
610 for (i=0;i<s1->all_eas.out.num_eas;i++) {
611 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
612 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
613 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
617 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
618 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
619 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
620 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
621 #stype1, #tfield1, #stype2, #tfield2, \
622 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
623 ret = False; \
625 s1 = fname_find(sname1); s2 = fname_find(sname2); \
626 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
627 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
628 #stype1, #tfield1, #stype2, #tfield2, \
629 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
630 ret = False; \
632 s1 = fnum_find(sname1); s2 = fname_find(sname2); \
633 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
634 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
635 #stype1, #tfield1, #stype2, #tfield2, \
636 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
637 ret = False; \
639 s1 = fname_find(sname1); s2 = fnum_find(sname2); \
640 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
641 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
642 #stype1, #tfield1, #stype2, #tfield2, \
643 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
644 ret = False; \
645 }} while (0)
647 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
648 "ALL_INFO", all_info, delete_pending);
649 VAL_CHECK("STANDARD_INFO", standard_info, directory,
650 "ALL_INFO", all_info, directory);
651 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
652 "ALL_INFO", all_info, nlink);
653 VAL_CHECK("EA_INFO", ea_info, ea_size,
654 "ALL_INFO", all_info, ea_size);
655 VAL_CHECK("EA_SIZE", ea_size, ea_size,
656 "ALL_INFO", all_info, ea_size);
659 #define NAME_PATH_CHECK(sname, stype, field) do { \
660 s1 = fname_find(sname); s2 = fnum_find(sname); \
661 if (s1 && s2) { \
662 VAL_EQUAL(stype, field, stype, field); \
664 } while (0)
667 s1 = fnum_find("INTERNAL_INFORMATION");
668 if (s1) {
669 printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
672 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
673 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
674 if (s1 && s2) {
675 printf("fnum pos = %.0f, fname pos = %.0f\n",
676 (double)s2->position_information.out.position,
677 (double)s1->position_information.out.position );
679 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
680 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
681 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
682 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
684 #if 0
685 /* these are expected to differ */
686 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
687 #endif
689 #if 0 /* unused */
690 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
691 s1 = fnum_find(sname); \
692 if (s1 && s1->stype.out.tfield != 0) { \
693 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
694 #stype, #tfield, \
695 (uint_t)s1->stype.out.tfield); \
697 s1 = fname_find(sname); \
698 if (s1 && s1->stype.out.tfield != 0) { \
699 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
700 #stype, #tfield, \
701 (uint_t)s1->stype.out.tfield); \
702 }} while (0)
703 #endif
704 /* now get a bit fancier .... */
706 /* when we set the delete disposition then the link count should drop
707 to 0 and delete_pending should be 1 */
710 done:
712 return ret;
715 /* basic testing of all RAW_FILEINFO_* calls
716 for each call we test that it succeeds, and where possible test
717 for consistency between the calls.
719 BOOL torture_raw_qfileinfo(struct torture_context *torture)
721 struct smbcli_state *cli;
722 BOOL ret = True;
723 TALLOC_CTX *mem_ctx;
724 int fnum;
725 const char *fname = "\\torture_qfileinfo.txt";
727 is_ipc = 0;
729 if (!torture_open_connection(&cli, 0)) {
730 return False;
733 mem_ctx = talloc_init("torture_qfileinfo");
735 fnum = create_complex_file(cli, mem_ctx, fname);
736 if (fnum == -1) {
737 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
738 ret = False;
739 goto done;
742 ret = torture_raw_qfileinfo_internals(torture, mem_ctx, cli->tree, fnum, fname);
744 smbcli_close(cli->tree, fnum);
745 smbcli_unlink(cli->tree, fname);
747 done:
748 torture_close_connection(cli);
749 talloc_free(mem_ctx);
750 return ret;
753 BOOL torture_raw_qfileinfo_pipe(struct torture_context *torture)
755 TALLOC_CTX *mem_ctx;
756 BOOL ret = True;
757 int fnum;
758 const char *fname = "\\lsass";
759 struct smbcli_state *cli;
760 struct dcerpc_pipe *p;
761 struct smbcli_tree *ipc_tree;
762 NTSTATUS status;
764 is_ipc = True;
766 if (!torture_open_connection(&cli, 0)) {
767 return False;
770 mem_ctx = talloc_init("torture_qfileinfo_pipe");
772 if (!(p = dcerpc_pipe_init(mem_ctx,
773 cli->tree->session->transport->socket->event.ctx))) {
774 return False;
777 status = dcerpc_pipe_open_smb(p, cli->tree, fname);
778 if (!NT_STATUS_IS_OK(status)) {
779 d_printf("dcerpc_pipe_open_smb failed: %s\n",
780 nt_errstr(status));
781 talloc_free(p);
782 return False;
785 ipc_tree = dcerpc_smb_tree(p->conn);
786 fnum = dcerpc_smb_fnum(p->conn);
788 ret = torture_raw_qfileinfo_internals(torture, mem_ctx, ipc_tree, fnum, fname);
790 talloc_free(p);
791 return ret;