LDB:tools - change counters to be unsigned
[Samba/ekacnet.git] / source4 / torture / raw / qfileinfo.c
blob86cae383ffb82152bac1fe28508ffc412cc96524
1 /*
2 Unix SMB/CIFS implementation.
3 RAW_FILEINFO_* individual test suite
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
26 #include "torture/rpc/rpc.h"
27 #include "param/param.h"
29 static struct {
30 const char *name;
31 enum smb_fileinfo_level level;
32 unsigned int only_paths:1;
33 unsigned int only_handles:1;
34 uint32_t capability_mask;
35 unsigned int expected_ipc_access_denied:1;
36 NTSTATUS expected_ipc_fnum_status;
37 NTSTATUS fnum_status, fname_status;
38 union smb_fileinfo fnum_finfo, fname_finfo;
39 } levels[] = {
40 { .name = "GETATTR",
41 .level = RAW_FILEINFO_GETATTR,
42 .only_paths = 1,
43 .only_handles = 0,
44 .expected_ipc_access_denied = 1},
45 { .name ="GETATTRE",
46 .level = RAW_FILEINFO_GETATTRE,
47 .only_paths = 0,
48 .only_handles = 1 },
49 { .name ="STANDARD",
50 .level = RAW_FILEINFO_STANDARD, },
51 { .name ="EA_SIZE",
52 .level = RAW_FILEINFO_EA_SIZE },
53 { .name ="ALL_EAS",
54 .level = RAW_FILEINFO_ALL_EAS,
55 .expected_ipc_fnum_status = NT_STATUS_ACCESS_DENIED,
57 { .name ="IS_NAME_VALID",
58 .level = RAW_FILEINFO_IS_NAME_VALID,
59 .only_paths = 1,
60 .only_handles = 0 },
61 { .name ="BASIC_INFO",
62 .level = RAW_FILEINFO_BASIC_INFO },
63 { .name ="STANDARD_INFO",
64 .level = RAW_FILEINFO_STANDARD_INFO },
65 { .name ="EA_INFO",
66 .level = RAW_FILEINFO_EA_INFO },
67 { .name ="NAME_INFO",
68 .level = RAW_FILEINFO_NAME_INFO },
69 { .name ="ALL_INFO",
70 .level = RAW_FILEINFO_ALL_INFO },
71 { .name ="ALT_NAME_INFO",
72 .level = RAW_FILEINFO_ALT_NAME_INFO,
73 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
75 { .name ="STREAM_INFO",
76 .level = RAW_FILEINFO_STREAM_INFO,
77 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
79 { .name ="COMPRESSION_INFO",
80 .level = RAW_FILEINFO_COMPRESSION_INFO,
81 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
83 { .name ="UNIX_BASIC_INFO",
84 .level = RAW_FILEINFO_UNIX_BASIC,
85 .only_paths = 0,
86 .only_handles = 0,
87 .capability_mask = CAP_UNIX},
88 { .name ="UNIX_LINK_INFO",
89 .level = RAW_FILEINFO_UNIX_LINK,
90 .only_paths = 0,
91 .only_handles = 0,
92 .capability_mask = CAP_UNIX},
93 { .name ="BASIC_INFORMATION",
94 .level = RAW_FILEINFO_BASIC_INFORMATION },
95 { .name ="STANDARD_INFORMATION",
96 .level = RAW_FILEINFO_STANDARD_INFORMATION },
97 { .name ="INTERNAL_INFORMATION",
98 .level = RAW_FILEINFO_INTERNAL_INFORMATION },
99 { .name ="EA_INFORMATION",
100 .level = RAW_FILEINFO_EA_INFORMATION },
101 { .name = "ACCESS_INFORMATION",
102 .level = RAW_FILEINFO_ACCESS_INFORMATION },
103 { .name = "NAME_INFORMATION",
104 .level = RAW_FILEINFO_NAME_INFORMATION },
105 { .name ="POSITION_INFORMATION",
106 .level = RAW_FILEINFO_POSITION_INFORMATION },
107 { .name ="MODE_INFORMATION",
108 .level = RAW_FILEINFO_MODE_INFORMATION },
109 { .name ="ALIGNMENT_INFORMATION",
110 .level = RAW_FILEINFO_ALIGNMENT_INFORMATION },
111 { .name ="ALL_INFORMATION",
112 .level = RAW_FILEINFO_ALL_INFORMATION },
113 { .name ="ALT_NAME_INFORMATION",
114 .level = RAW_FILEINFO_ALT_NAME_INFORMATION,
115 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
117 { .name ="STREAM_INFORMATION",
118 .level = RAW_FILEINFO_STREAM_INFORMATION,
119 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
121 { .name = "COMPRESSION_INFORMATION",
122 .level = RAW_FILEINFO_COMPRESSION_INFORMATION,
123 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
125 { .name ="NETWORK_OPEN_INFORMATION",
126 .level = RAW_FILEINFO_NETWORK_OPEN_INFORMATION,
127 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
129 { .name = "ATTRIBUTE_TAG_INFORMATION",
130 .level = RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION,
131 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
133 { NULL }
137 compare a dos time (2 second resolution) to a nt time
139 static int dos_nt_time_cmp(time_t t, NTTIME nt)
141 time_t t2 = nt_time_to_unix(nt);
142 if (abs(t2 - t) <= 2) return 0;
143 return t2 > t ? 1 : -1;
148 find a level in the levels[] table
150 static union smb_fileinfo *fnum_find(const char *name)
152 int i;
153 for (i=0; levels[i].name; i++) {
154 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
155 strcmp(name, levels[i].name) == 0 &&
156 !levels[i].only_paths) {
157 return &levels[i].fnum_finfo;
160 return NULL;
164 find a level in the levels[] table
166 static union smb_fileinfo *fname_find(bool is_ipc, const char *name)
168 int i;
169 if (is_ipc) {
170 return NULL;
172 for (i=0; levels[i].name; i++) {
173 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
174 strcmp(name, levels[i].name) == 0 &&
175 !levels[i].only_handles) {
176 return &levels[i].fname_finfo;
179 return NULL;
182 /* local macros to make the code below more readable */
183 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
184 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
185 #n1, #v1, (unsigned int)s1->n1.out.v1, \
186 #n2, #v2, (unsigned int)s2->n2.out.v2, \
187 __FILE__, __LINE__); \
188 ret = false; \
189 }} while(0)
191 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
192 s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
193 printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
194 #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
195 #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
196 __FILE__, __LINE__); \
197 ret = false; \
198 }} while(0)
200 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
201 printf("%s/%s != %s/%s at %s(%d)\n", \
202 #n1, #v1, \
203 #n2, #v2, \
204 __FILE__, __LINE__); \
205 ret = false; \
206 }} while(0)
208 /* used to find hints on unknown values - and to make sure
209 we zero-fill */
210 #if 0 /* unused */
211 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
212 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
213 #n1, #v1, \
214 (unsigned int)s1->n1.out.v1, \
215 (unsigned int)s1->n1.out.v1, \
216 __FILE__, __LINE__); \
217 ret = false; \
218 }} while(0)
219 #endif
221 /* basic testing of all RAW_FILEINFO_* calls
222 for each call we test that it succeeds, and where possible test
223 for consistency between the calls.
225 static bool torture_raw_qfileinfo_internals(struct torture_context *torture,
226 TALLOC_CTX *mem_ctx,
227 struct smbcli_tree *tree,
228 int fnum, const char *fname,
229 bool is_ipc)
231 int i;
232 bool ret = true;
233 int count;
234 union smb_fileinfo *s1, *s2;
235 NTTIME correct_time;
236 uint64_t correct_size;
237 uint32_t correct_attrib;
238 const char *correct_name;
239 bool skip_streams = false;
241 /* scan all the fileinfo and pathinfo levels */
242 for (i=0; levels[i].name; i++) {
243 if (!levels[i].only_paths) {
244 levels[i].fnum_finfo.generic.level = levels[i].level;
245 levels[i].fnum_finfo.generic.in.file.fnum = fnum;
246 levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx,
247 &levels[i].fnum_finfo);
250 if (!levels[i].only_handles) {
251 levels[i].fname_finfo.generic.level = levels[i].level;
252 levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
253 levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx,
254 &levels[i].fname_finfo);
258 /* check for completely broken levels */
259 for (count=i=0; levels[i].name; i++) {
260 uint32_t cap = tree->session->transport->negotiate.capabilities;
261 /* see if this server claims to support this level */
262 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
263 continue;
266 if (is_ipc) {
267 if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
268 } else if (!levels[i].only_handles &&
269 NT_STATUS_EQUAL(levels[i].fname_status,
270 NT_STATUS_NOT_SUPPORTED)) {
271 torture_warning(torture, "fname level %s %s",
272 levels[i].name,
273 nt_errstr(levels[i].fname_status));
274 continue;
275 } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
276 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n",
277 levels[i].name, nt_errstr(levels[i].fname_status));
278 count++;
280 if (!levels[i].only_paths &&
281 NT_STATUS_EQUAL(levels[i].fnum_status,
282 NT_STATUS_NOT_SUPPORTED)) {
283 torture_warning(torture, "fnum level %s %s",
284 levels[i].name,
285 nt_errstr(levels[i].fnum_status));
286 continue;
288 if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
289 printf("ERROR: fnum level %s failed, expected %s - %s\n",
290 levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status),
291 nt_errstr(levels[i].fnum_status));
292 count++;
294 } else {
295 if (!levels[i].only_paths &&
296 NT_STATUS_EQUAL(levels[i].fnum_status,
297 NT_STATUS_NOT_SUPPORTED)) {
298 torture_warning(torture, "fnum level %s %s",
299 levels[i].name,
300 nt_errstr(levels[i].fnum_status));
301 continue;
304 if (!levels[i].only_handles &&
305 NT_STATUS_EQUAL(levels[i].fname_status,
306 NT_STATUS_NOT_SUPPORTED)) {
307 torture_warning(torture, "fname level %s %s",
308 levels[i].name,
309 nt_errstr(levels[i].fname_status));
310 continue;
313 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
314 printf("ERROR: fnum level %s failed - %s\n",
315 levels[i].name, nt_errstr(levels[i].fnum_status));
316 count++;
318 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
319 printf("ERROR: fname level %s failed - %s\n",
320 levels[i].name, nt_errstr(levels[i].fname_status));
321 count++;
327 if (count != 0) {
328 ret = false;
329 printf("%d levels failed\n", count);
330 if (count > 35) {
331 torture_fail(torture, "too many level failures - giving up");
335 /* see if we can do streams */
336 s1 = fnum_find("STREAM_INFO");
337 if (!s1 || s1->stream_info.out.num_streams == 0) {
338 if (!is_ipc) {
339 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
340 s1 ? s1->stream_info.out.num_streams : -1);
342 skip_streams = true;
346 /* this code is incredibly repititive but doesn't lend itself to loops, so
347 we use lots of macros to make it less painful */
349 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
350 this code to fail, but we need to check it for completeness */
354 #define ALIAS_CHECK(sname1, sname2) \
355 do { \
356 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
357 if (s1 && s2) { INFO_CHECK } \
358 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
359 if (s1 && s2) { INFO_CHECK } \
360 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
361 if (s1 && s2) { INFO_CHECK } \
362 } while (0)
364 #define INFO_CHECK \
365 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
366 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
367 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
368 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
369 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
371 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
373 #undef INFO_CHECK
374 #define INFO_CHECK \
375 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
376 VAL_EQUAL(standard_info, size, standard_info, size); \
377 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
378 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
379 VAL_EQUAL(standard_info, directory, standard_info, directory);
381 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
383 #undef INFO_CHECK
384 #define INFO_CHECK \
385 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
387 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
389 #undef INFO_CHECK
390 #define INFO_CHECK \
391 STR_EQUAL(name_info, fname, name_info, fname);
393 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
395 #undef INFO_CHECK
396 #define INFO_CHECK \
397 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
398 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
399 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
400 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
401 VAL_EQUAL(all_info, attrib, all_info, attrib); \
402 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
403 VAL_EQUAL(all_info, size, all_info, size); \
404 VAL_EQUAL(all_info, nlink, all_info, nlink); \
405 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
406 VAL_EQUAL(all_info, directory, all_info, directory); \
407 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
408 STR_EQUAL(all_info, fname, all_info, fname);
410 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
412 #undef INFO_CHECK
413 #define INFO_CHECK \
414 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
415 VAL_EQUAL(compression_info, format, compression_info, format); \
416 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
417 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
418 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
420 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
423 #undef INFO_CHECK
424 #define INFO_CHECK \
425 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
427 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
430 #define TIME_CHECK_NT(sname, stype, tfield) do { \
431 s1 = fnum_find(sname); \
432 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
433 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
434 nt_time_string(mem_ctx, s1->stype.out.tfield), \
435 nt_time_string(mem_ctx, correct_time)); \
436 ret = false; \
438 s1 = fname_find(is_ipc, sname); \
439 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
440 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
441 nt_time_string(mem_ctx, s1->stype.out.tfield), \
442 nt_time_string(mem_ctx, correct_time)); \
443 ret = false; \
444 }} while (0)
446 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
447 s1 = fnum_find(sname); \
448 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
449 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
450 timestring(mem_ctx, s1->stype.out.tfield), \
451 nt_time_string(mem_ctx, correct_time)); \
452 ret = false; \
454 s1 = fname_find(is_ipc, sname); \
455 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
456 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
457 timestring(mem_ctx, s1->stype.out.tfield), \
458 nt_time_string(mem_ctx, correct_time)); \
459 ret = false; \
460 }} while (0)
462 #if 0 /* unused */
463 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
464 s1 = fnum_find(sname); \
465 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
466 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
467 timestring(mem_ctx, s1->stype.out.tfield), \
468 nt_time_string(mem_ctx, correct_time)); \
469 ret = false; \
471 s1 = fname_find(is_ipc, sname); \
472 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
473 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
474 timestring(mem_ctx, s1->stype.out.tfield), \
475 nt_time_string(mem_ctx, correct_time)); \
476 ret = false; \
477 }} while (0)
478 #endif
480 /* now check that all the times that are supposed to be equal are correct */
481 s1 = fnum_find("BASIC_INFO");
482 correct_time = s1->basic_info.out.create_time;
483 torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time));
485 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
486 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
487 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
488 TIME_CHECK_DOS("STANDARD", standard, create_time);
489 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
490 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
491 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
493 s1 = fnum_find("BASIC_INFO");
494 correct_time = s1->basic_info.out.access_time;
495 torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time));
497 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
498 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
499 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
500 TIME_CHECK_DOS("STANDARD", standard, access_time);
501 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
502 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
503 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
505 s1 = fnum_find("BASIC_INFO");
506 correct_time = s1->basic_info.out.write_time;
507 torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time));
509 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
510 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
511 TIME_CHECK_DOS("GETATTR", getattr, write_time);
512 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
513 TIME_CHECK_DOS("STANDARD", standard, write_time);
514 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
515 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
516 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
518 s1 = fnum_find("BASIC_INFO");
519 correct_time = s1->basic_info.out.change_time;
520 torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time));
522 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
523 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
524 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
525 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
528 #define SIZE_CHECK(sname, stype, tfield) do { \
529 s1 = fnum_find(sname); \
530 if (s1 && s1->stype.out.tfield != correct_size) { \
531 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
532 (unsigned int)s1->stype.out.tfield, \
533 (unsigned int)correct_size); \
534 ret = false; \
536 s1 = fname_find(is_ipc, sname); \
537 if (s1 && s1->stype.out.tfield != correct_size) { \
538 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
539 (unsigned int)s1->stype.out.tfield, \
540 (unsigned int)correct_size); \
541 ret = false; \
542 }} while (0)
544 s1 = fnum_find("STANDARD_INFO");
545 correct_size = s1->standard_info.out.size;
546 torture_comment(torture, "size: %u\n", (unsigned int)correct_size);
548 SIZE_CHECK("GETATTR", getattr, size);
549 SIZE_CHECK("GETATTRE", getattre, size);
550 SIZE_CHECK("STANDARD", standard, size);
551 SIZE_CHECK("EA_SIZE", ea_size, size);
552 SIZE_CHECK("STANDARD_INFO", standard_info, size);
553 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
554 SIZE_CHECK("ALL_INFO", all_info, size);
555 SIZE_CHECK("ALL_INFORMATION", all_info, size);
556 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
557 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
558 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
559 if (!skip_streams) {
560 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
561 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
565 s1 = fnum_find("STANDARD_INFO");
566 correct_size = s1->standard_info.out.alloc_size;
567 torture_comment(torture, "alloc_size: %u\n", (unsigned int)correct_size);
569 SIZE_CHECK("GETATTRE", getattre, alloc_size);
570 SIZE_CHECK("STANDARD", standard, alloc_size);
571 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
572 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
573 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
574 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
575 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
576 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
577 if (!skip_streams) {
578 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
579 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
582 #define ATTRIB_CHECK(sname, stype, tfield) do { \
583 s1 = fnum_find(sname); \
584 if (s1 && s1->stype.out.tfield != correct_attrib) { \
585 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
586 (unsigned int)s1->stype.out.tfield, \
587 (unsigned int)correct_attrib); \
588 ret = false; \
590 s1 = fname_find(is_ipc, sname); \
591 if (s1 && s1->stype.out.tfield != correct_attrib) { \
592 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
593 (unsigned int)s1->stype.out.tfield, \
594 (unsigned int)correct_attrib); \
595 ret = false; \
596 }} while (0)
598 s1 = fnum_find("BASIC_INFO");
599 correct_attrib = s1->basic_info.out.attrib;
600 torture_comment(torture, "attrib: 0x%x\n", (unsigned int)correct_attrib);
602 ATTRIB_CHECK("GETATTR", getattr, attrib);
603 if (!is_ipc) {
604 ATTRIB_CHECK("GETATTRE", getattre, attrib);
605 ATTRIB_CHECK("STANDARD", standard, attrib);
606 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
608 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
609 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
610 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
611 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
612 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
613 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
615 correct_name = fname;
616 torture_comment(torture, "name: %s\n", correct_name);
618 #define NAME_CHECK(sname, stype, tfield, flags) do { \
619 s1 = fnum_find(sname); \
620 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
621 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
622 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
623 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
624 ret = false; \
626 s1 = fname_find(is_ipc, sname); \
627 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
628 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
629 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
630 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
631 ret = false; \
632 }} while (0)
634 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
635 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
637 /* the ALL_INFO file name is the full path on the filesystem */
638 s1 = fnum_find("ALL_INFO");
639 if (s1 && !s1->all_info.out.fname.s) {
640 torture_fail(torture, "ALL_INFO didn't give a filename");
642 if (s1 && s1->all_info.out.fname.s) {
643 char *p = strrchr(s1->all_info.out.fname.s, '\\');
644 if (!p) {
645 printf("Not a full path in all_info/fname? - '%s'\n",
646 s1->all_info.out.fname.s);
647 ret = false;
648 } else {
649 if (strcmp_safe(correct_name, p) != 0) {
650 printf("incorrect basename in all_info/fname - '%s'\n",
651 s1->all_info.out.fname.s);
652 ret = false;
655 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
656 printf("Should not null terminate all_info/fname\n");
657 ret = false;
661 s1 = fnum_find("ALT_NAME_INFO");
662 if (s1) {
663 correct_name = s1->alt_name_info.out.fname.s;
664 torture_comment(torture, "alt_name: %s\n", correct_name);
666 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
667 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
669 /* and make sure we can open by alternate name */
670 smbcli_close(tree, fnum);
671 fnum = smbcli_nt_create_full(tree, correct_name, 0,
672 SEC_RIGHTS_FILE_ALL,
673 FILE_ATTRIBUTE_NORMAL,
674 NTCREATEX_SHARE_ACCESS_DELETE|
675 NTCREATEX_SHARE_ACCESS_READ|
676 NTCREATEX_SHARE_ACCESS_WRITE,
677 NTCREATEX_DISP_OVERWRITE_IF,
678 0, 0);
679 if (fnum == -1) {
680 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
681 ret = false;
684 if (!skip_streams) {
685 correct_name = "::$DATA";
686 torture_comment(torture, "stream_name: %s\n", correct_name);
688 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
689 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
693 /* make sure the EAs look right */
694 s1 = fnum_find("ALL_EAS");
695 s2 = fnum_find("ALL_INFO");
696 if (s1) {
697 for (i=0;i<s1->all_eas.out.num_eas;i++) {
698 printf(" flags=%d %s=%*.*s\n",
699 s1->all_eas.out.eas[i].flags,
700 s1->all_eas.out.eas[i].name.s,
701 (int)s1->all_eas.out.eas[i].value.length,
702 (int)s1->all_eas.out.eas[i].value.length,
703 s1->all_eas.out.eas[i].value.data);
706 if (s1 && s2) {
707 if (s1->all_eas.out.num_eas == 0) {
708 if (s2->all_info.out.ea_size != 0) {
709 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
710 s2->all_info.out.ea_size);
712 } else {
713 if (s2->all_info.out.ea_size !=
714 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
715 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
716 (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
717 (int)s2->all_info.out.ea_size);
721 s2 = fname_find(is_ipc, "ALL_EAS");
722 if (s2) {
723 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
724 for (i=0;i<s1->all_eas.out.num_eas;i++) {
725 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
726 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
727 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
731 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
732 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
733 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
734 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
735 #stype1, #tfield1, #stype2, #tfield2, \
736 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
737 ret = false; \
739 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
740 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
741 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
742 #stype1, #tfield1, #stype2, #tfield2, \
743 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
744 ret = false; \
746 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
747 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
748 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
749 #stype1, #tfield1, #stype2, #tfield2, \
750 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
751 ret = false; \
753 s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
754 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
755 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
756 #stype1, #tfield1, #stype2, #tfield2, \
757 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
758 ret = false; \
759 }} while (0)
761 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
762 "ALL_INFO", all_info, delete_pending);
763 VAL_CHECK("STANDARD_INFO", standard_info, directory,
764 "ALL_INFO", all_info, directory);
765 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
766 "ALL_INFO", all_info, nlink);
767 s1 = fnum_find("BASIC_INFO");
768 if (s1 && is_ipc) {
769 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
770 printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
771 ret = false;
774 s1 = fnum_find("STANDARD_INFO");
775 if (s1 && is_ipc) {
776 if (s1->standard_info.out.nlink != 1) {
777 printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
778 ret = false;
780 if (s1->standard_info.out.delete_pending != 1) {
781 printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
782 ret = false;
785 VAL_CHECK("EA_INFO", ea_info, ea_size,
786 "ALL_INFO", all_info, ea_size);
787 if (!is_ipc) {
788 VAL_CHECK("EA_SIZE", ea_size, ea_size,
789 "ALL_INFO", all_info, ea_size);
792 #define NAME_PATH_CHECK(sname, stype, field) do { \
793 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
794 if (s1 && s2) { \
795 VAL_EQUAL(stype, field, stype, field); \
797 } while (0)
800 s1 = fnum_find("INTERNAL_INFORMATION");
801 if (s1) {
802 torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id);
805 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
806 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
807 if (s1 && s2) {
808 printf("fnum pos = %.0f, fname pos = %.0f\n",
809 (double)s2->position_information.out.position,
810 (double)s1->position_information.out.position );
812 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
813 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
814 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
815 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
817 #if 0
818 /* these are expected to differ */
819 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
820 #endif
822 #if 0 /* unused */
823 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
824 s1 = fnum_find(sname); \
825 if (s1 && s1->stype.out.tfield != 0) { \
826 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
827 #stype, #tfield, \
828 (unsigned int)s1->stype.out.tfield); \
830 s1 = fname_find(is_ipc, sname); \
831 if (s1 && s1->stype.out.tfield != 0) { \
832 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
833 #stype, #tfield, \
834 (unsigned int)s1->stype.out.tfield); \
835 }} while (0)
836 #endif
837 /* now get a bit fancier .... */
839 /* when we set the delete disposition then the link count should drop
840 to 0 and delete_pending should be 1 */
842 return ret;
845 /* basic testing of all RAW_FILEINFO_* calls
846 for each call we test that it succeeds, and where possible test
847 for consistency between the calls.
849 bool torture_raw_qfileinfo(struct torture_context *torture,
850 struct smbcli_state *cli)
852 int fnum;
853 bool ret;
854 const char *fname = "\\torture_qfileinfo.txt";
856 fnum = create_complex_file(cli, torture, fname);
857 if (fnum == -1) {
858 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
859 return false;
862 ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */);
864 smbcli_close(cli->tree, fnum);
865 smbcli_unlink(cli->tree, fname);
867 return ret;
870 bool torture_raw_qfileinfo_pipe(struct torture_context *torture,
871 struct smbcli_state *cli)
873 bool ret = true;
874 int fnum;
875 const char *fname = "\\lsass";
876 struct dcerpc_pipe *p;
877 struct smbcli_tree *ipc_tree;
878 NTSTATUS status;
880 if (!(p = dcerpc_pipe_init(torture, cli->tree->session->transport->socket->event.ctx,
881 lp_iconv_convenience(torture->lp_ctx)))) {
882 return false;
885 status = dcerpc_pipe_open_smb(p, cli->tree, fname);
886 torture_assert_ntstatus_ok(torture, status, "dcerpc_pipe_open_smb failed");
888 ipc_tree = dcerpc_smb_tree(p->conn);
889 fnum = dcerpc_smb_fnum(p->conn);
891 ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, true /* is_ipc */);
893 talloc_free(p);
894 return ret;