source: trunk/server/source4/torture/raw/qfileinfo.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 34.3 KB
Line 
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
6
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.
11
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.
16
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/>.
19*/
20
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/torture_rpc.h"
27#include "param/param.h"
28
29static 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,
56 },
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
74 },
75 { .name ="STREAM_INFO",
76 .level = RAW_FILEINFO_STREAM_INFO,
77 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
78 },
79 { .name ="COMPRESSION_INFO",
80 .level = RAW_FILEINFO_COMPRESSION_INFO,
81 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
82 },
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
116 },
117 { .name ="STREAM_INFORMATION",
118 .level = RAW_FILEINFO_STREAM_INFORMATION,
119 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
120 },
121 { .name = "COMPRESSION_INFORMATION",
122 .level = RAW_FILEINFO_COMPRESSION_INFORMATION,
123 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
124 },
125 { .name ="NETWORK_OPEN_INFORMATION",
126 .level = RAW_FILEINFO_NETWORK_OPEN_INFORMATION,
127 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
128 },
129 { .name = "ATTRIBUTE_TAG_INFORMATION",
130 .level = RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION,
131 .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
132 },
133 { NULL }
134};
135
136/*
137 compare a dos time (2 second resolution) to a nt time
138*/
139static int dos_nt_time_cmp(time_t t, NTTIME nt)
140{
141 time_t t2 = nt_time_to_unix(nt);
142 if (abs(t2 - t) <= 2) return 0;
143 return t2 > t ? 1 : -1;
144}
145
146
147/*
148 find a level in the levels[] table
149*/
150static union smb_fileinfo *fnum_find(const char *name)
151{
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;
158 }
159 }
160 return NULL;
161}
162
163/*
164 find a level in the levels[] table
165*/
166static union smb_fileinfo *fname_find(bool is_ipc, const char *name)
167{
168 int i;
169 if (is_ipc) {
170 return NULL;
171 }
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;
177 }
178 }
179 return NULL;
180}
181
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)
190
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)
199
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)
207
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
220
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.
224*/
225static 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)
230{
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;
240
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);
248 }
249
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);
255 }
256 }
257
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;
264 }
265
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++;
279 }
280 if (!levels[i].only_paths &&
281 (NT_STATUS_EQUAL(levels[i].fnum_status,
282 NT_STATUS_NOT_SUPPORTED) ||
283 NT_STATUS_EQUAL(levels[i].fnum_status,
284 NT_STATUS_NOT_IMPLEMENTED))) {
285 torture_warning(torture, "fnum level %s %s",
286 levels[i].name,
287 nt_errstr(levels[i].fnum_status));
288 continue;
289 }
290 if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
291 printf("ERROR: fnum level %s failed, expected %s - %s\n",
292 levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status),
293 nt_errstr(levels[i].fnum_status));
294 count++;
295 }
296 } else {
297 if (!levels[i].only_paths &&
298 (NT_STATUS_EQUAL(levels[i].fnum_status,
299 NT_STATUS_NOT_SUPPORTED) ||
300 NT_STATUS_EQUAL(levels[i].fnum_status,
301 NT_STATUS_NOT_IMPLEMENTED))) {
302 torture_warning(torture, "fnum level %s %s",
303 levels[i].name,
304 nt_errstr(levels[i].fnum_status));
305 continue;
306 }
307
308 if (!levels[i].only_handles &&
309 (NT_STATUS_EQUAL(levels[i].fname_status,
310 NT_STATUS_NOT_SUPPORTED) ||
311 NT_STATUS_EQUAL(levels[i].fname_status,
312 NT_STATUS_NOT_IMPLEMENTED))) {
313 torture_warning(torture, "fname level %s %s",
314 levels[i].name,
315 nt_errstr(levels[i].fname_status));
316 continue;
317 }
318
319 if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
320 printf("ERROR: fnum level %s failed - %s\n",
321 levels[i].name, nt_errstr(levels[i].fnum_status));
322 count++;
323 }
324 if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
325 printf("ERROR: fname level %s failed - %s\n",
326 levels[i].name, nt_errstr(levels[i].fname_status));
327 count++;
328 }
329 }
330
331 }
332
333 if (count != 0) {
334 ret = false;
335 printf("%d levels failed\n", count);
336 if (count > 35) {
337 torture_fail(torture, "too many level failures - giving up");
338 }
339 }
340
341 /* see if we can do streams */
342 s1 = fnum_find("STREAM_INFO");
343 if (!s1 || s1->stream_info.out.num_streams == 0) {
344 if (!is_ipc) {
345 printf("STREAM_INFO broken (%d) - skipping streams checks\n",
346 s1 ? s1->stream_info.out.num_streams : -1);
347 }
348 skip_streams = true;
349 }
350
351
352 /* this code is incredibly repititive but doesn't lend itself to loops, so
353 we use lots of macros to make it less painful */
354
355 /* first off we check the levels that are supposed to be aliases. It will be quite rare for
356 this code to fail, but we need to check it for completeness */
357
358
359
360#define ALIAS_CHECK(sname1, sname2) \
361 do { \
362 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
363 if (s1 && s2) { INFO_CHECK } \
364 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
365 if (s1 && s2) { INFO_CHECK } \
366 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
367 if (s1 && s2) { INFO_CHECK } \
368 } while (0)
369
370#define INFO_CHECK \
371 STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
372 STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
373 STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
374 STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
375 VAL_EQUAL (basic_info, attrib, basic_info, attrib);
376
377 ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
378
379#undef INFO_CHECK
380#define INFO_CHECK \
381 VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
382 VAL_EQUAL(standard_info, size, standard_info, size); \
383 VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
384 VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
385 VAL_EQUAL(standard_info, directory, standard_info, directory);
386
387 ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
388
389#undef INFO_CHECK
390#define INFO_CHECK \
391 VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
392
393 ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
394
395#undef INFO_CHECK
396#define INFO_CHECK \
397 STR_EQUAL(name_info, fname, name_info, fname);
398
399 ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
400
401#undef INFO_CHECK
402#define INFO_CHECK \
403 STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
404 STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
405 STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
406 STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
407 VAL_EQUAL(all_info, attrib, all_info, attrib); \
408 VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
409 VAL_EQUAL(all_info, size, all_info, size); \
410 VAL_EQUAL(all_info, nlink, all_info, nlink); \
411 VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
412 VAL_EQUAL(all_info, directory, all_info, directory); \
413 VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
414 STR_EQUAL(all_info, fname, all_info, fname);
415
416 ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
417
418#undef INFO_CHECK
419#define INFO_CHECK \
420 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
421 VAL_EQUAL(compression_info, format, compression_info, format); \
422 VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
423 VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
424 VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
425
426 ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
427
428
429#undef INFO_CHECK
430#define INFO_CHECK \
431 STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
432
433 ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
434
435
436#define TIME_CHECK_NT(sname, stype, tfield) do { \
437 s1 = fnum_find(sname); \
438 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
439 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
440 nt_time_string(mem_ctx, s1->stype.out.tfield), \
441 nt_time_string(mem_ctx, correct_time)); \
442 ret = false; \
443 } \
444 s1 = fname_find(is_ipc, sname); \
445 if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
446 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
447 nt_time_string(mem_ctx, s1->stype.out.tfield), \
448 nt_time_string(mem_ctx, correct_time)); \
449 ret = false; \
450 }} while (0)
451
452#define TIME_CHECK_DOS(sname, stype, tfield) do { \
453 s1 = fnum_find(sname); \
454 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
455 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
456 timestring(mem_ctx, s1->stype.out.tfield), \
457 nt_time_string(mem_ctx, correct_time)); \
458 ret = false; \
459 } \
460 s1 = fname_find(is_ipc, sname); \
461 if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
462 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
463 timestring(mem_ctx, s1->stype.out.tfield), \
464 nt_time_string(mem_ctx, correct_time)); \
465 ret = false; \
466 }} while (0)
467
468#if 0 /* unused */
469#define TIME_CHECK_UNX(sname, stype, tfield) do { \
470 s1 = fnum_find(sname); \
471 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
472 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
473 timestring(mem_ctx, s1->stype.out.tfield), \
474 nt_time_string(mem_ctx, correct_time)); \
475 ret = false; \
476 } \
477 s1 = fname_find(is_ipc, sname); \
478 if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
479 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
480 timestring(mem_ctx, s1->stype.out.tfield), \
481 nt_time_string(mem_ctx, correct_time)); \
482 ret = false; \
483 }} while (0)
484#endif
485
486 /* now check that all the times that are supposed to be equal are correct */
487 s1 = fnum_find("BASIC_INFO");
488 correct_time = s1->basic_info.out.create_time;
489 torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time));
490
491 TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
492 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
493 TIME_CHECK_DOS("GETATTRE", getattre, create_time);
494 TIME_CHECK_DOS("STANDARD", standard, create_time);
495 TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
496 TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
497 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
498
499 s1 = fnum_find("BASIC_INFO");
500 correct_time = s1->basic_info.out.access_time;
501 torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time));
502
503 TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
504 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
505 TIME_CHECK_DOS("GETATTRE", getattre, access_time);
506 TIME_CHECK_DOS("STANDARD", standard, access_time);
507 TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
508 TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
509 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
510
511 s1 = fnum_find("BASIC_INFO");
512 correct_time = s1->basic_info.out.write_time;
513 torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time));
514
515 TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
516 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
517 TIME_CHECK_DOS("GETATTR", getattr, write_time);
518 TIME_CHECK_DOS("GETATTRE", getattre, write_time);
519 TIME_CHECK_DOS("STANDARD", standard, write_time);
520 TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
521 TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
522 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
523
524 s1 = fnum_find("BASIC_INFO");
525 correct_time = s1->basic_info.out.change_time;
526 torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time));
527
528 TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
529 TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
530 TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
531 TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
532
533
534#define SIZE_CHECK(sname, stype, tfield) do { \
535 s1 = fnum_find(sname); \
536 if (s1 && s1->stype.out.tfield != correct_size) { \
537 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
538 (unsigned int)s1->stype.out.tfield, \
539 (unsigned int)correct_size); \
540 ret = false; \
541 } \
542 s1 = fname_find(is_ipc, sname); \
543 if (s1 && s1->stype.out.tfield != correct_size) { \
544 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
545 (unsigned int)s1->stype.out.tfield, \
546 (unsigned int)correct_size); \
547 ret = false; \
548 }} while (0)
549
550 s1 = fnum_find("STANDARD_INFO");
551 correct_size = s1->standard_info.out.size;
552 torture_comment(torture, "size: %u\n", (unsigned int)correct_size);
553
554 SIZE_CHECK("GETATTR", getattr, size);
555 SIZE_CHECK("GETATTRE", getattre, size);
556 SIZE_CHECK("STANDARD", standard, size);
557 SIZE_CHECK("EA_SIZE", ea_size, size);
558 SIZE_CHECK("STANDARD_INFO", standard_info, size);
559 SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
560 SIZE_CHECK("ALL_INFO", all_info, size);
561 SIZE_CHECK("ALL_INFORMATION", all_info, size);
562 SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
563 SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
564 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
565 if (!skip_streams) {
566 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
567 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
568 }
569
570
571 s1 = fnum_find("STANDARD_INFO");
572 correct_size = s1->standard_info.out.alloc_size;
573 torture_comment(torture, "alloc_size: %u\n", (unsigned int)correct_size);
574
575 SIZE_CHECK("GETATTRE", getattre, alloc_size);
576 SIZE_CHECK("STANDARD", standard, alloc_size);
577 SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
578 SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
579 SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
580 SIZE_CHECK("ALL_INFO", all_info, alloc_size);
581 SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
582 SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
583 if (!skip_streams) {
584 SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
585 SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
586 }
587
588#define ATTRIB_CHECK(sname, stype, tfield) do { \
589 s1 = fnum_find(sname); \
590 if (s1 && s1->stype.out.tfield != correct_attrib) { \
591 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
592 (unsigned int)s1->stype.out.tfield, \
593 (unsigned int)correct_attrib); \
594 ret = false; \
595 } \
596 s1 = fname_find(is_ipc, sname); \
597 if (s1 && s1->stype.out.tfield != correct_attrib) { \
598 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
599 (unsigned int)s1->stype.out.tfield, \
600 (unsigned int)correct_attrib); \
601 ret = false; \
602 }} while (0)
603
604 s1 = fnum_find("BASIC_INFO");
605 correct_attrib = s1->basic_info.out.attrib;
606 torture_comment(torture, "attrib: 0x%x\n", (unsigned int)correct_attrib);
607
608 ATTRIB_CHECK("GETATTR", getattr, attrib);
609 if (!is_ipc) {
610 ATTRIB_CHECK("GETATTRE", getattre, attrib);
611 ATTRIB_CHECK("STANDARD", standard, attrib);
612 ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
613 }
614 ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
615 ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
616 ATTRIB_CHECK("ALL_INFO", all_info, attrib);
617 ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
618 ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
619 ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
620
621 correct_name = fname;
622 torture_comment(torture, "name: %s\n", correct_name);
623
624#define NAME_CHECK(sname, stype, tfield, flags) do { \
625 s1 = fnum_find(sname); \
626 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
627 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
628 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
629 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
630 ret = false; \
631 } \
632 s1 = fname_find(is_ipc, sname); \
633 if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
634 wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
635 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
636 s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
637 ret = false; \
638 }} while (0)
639
640 NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
641 NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
642
643 /* the ALL_INFO file name is the full path on the filesystem */
644 s1 = fnum_find("ALL_INFO");
645 if (s1 && !s1->all_info.out.fname.s) {
646 torture_fail(torture, "ALL_INFO didn't give a filename");
647 }
648 if (s1 && s1->all_info.out.fname.s) {
649 char *p = strrchr(s1->all_info.out.fname.s, '\\');
650 if (!p) {
651 printf("Not a full path in all_info/fname? - '%s'\n",
652 s1->all_info.out.fname.s);
653 ret = false;
654 } else {
655 if (strcmp_safe(correct_name, p) != 0) {
656 printf("incorrect basename in all_info/fname - '%s'\n",
657 s1->all_info.out.fname.s);
658 ret = false;
659 }
660 }
661 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
662 printf("Should not null terminate all_info/fname\n");
663 ret = false;
664 }
665 }
666
667 s1 = fnum_find("ALT_NAME_INFO");
668 if (s1) {
669 correct_name = s1->alt_name_info.out.fname.s;
670 }
671
672 if (!correct_name) {
673 torture_comment(torture, "no alternate name information\n");
674 } else {
675 torture_comment(torture, "alt_name: %s\n", correct_name);
676
677 NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
678 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
679
680 /* and make sure we can open by alternate name */
681 smbcli_close(tree, fnum);
682 fnum = smbcli_nt_create_full(tree, correct_name, 0,
683 SEC_RIGHTS_FILE_ALL,
684 FILE_ATTRIBUTE_NORMAL,
685 NTCREATEX_SHARE_ACCESS_DELETE|
686 NTCREATEX_SHARE_ACCESS_READ|
687 NTCREATEX_SHARE_ACCESS_WRITE,
688 NTCREATEX_DISP_OVERWRITE_IF,
689 0, 0);
690 if (fnum == -1) {
691 printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
692 ret = false;
693 }
694
695 if (!skip_streams) {
696 correct_name = "::$DATA";
697 torture_comment(torture, "stream_name: %s\n", correct_name);
698
699 NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
700 NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
701 }
702 }
703
704 /* make sure the EAs look right */
705 s1 = fnum_find("ALL_EAS");
706 s2 = fnum_find("ALL_INFO");
707 if (s1) {
708 for (i=0;i<s1->all_eas.out.num_eas;i++) {
709 printf(" flags=%d %s=%*.*s\n",
710 s1->all_eas.out.eas[i].flags,
711 s1->all_eas.out.eas[i].name.s,
712 (int)s1->all_eas.out.eas[i].value.length,
713 (int)s1->all_eas.out.eas[i].value.length,
714 s1->all_eas.out.eas[i].value.data);
715 }
716 }
717 if (s1 && s2) {
718 if (s1->all_eas.out.num_eas == 0) {
719 if (s2->all_info.out.ea_size != 0) {
720 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
721 s2->all_info.out.ea_size);
722 }
723 } else {
724 if (s2->all_info.out.ea_size !=
725 ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
726 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
727 (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
728 (int)s2->all_info.out.ea_size);
729 }
730 }
731 }
732 s2 = fname_find(is_ipc, "ALL_EAS");
733 if (s2) {
734 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
735 for (i=0;i<s1->all_eas.out.num_eas;i++) {
736 VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
737 STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
738 VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
739 }
740 }
741
742#define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
743 s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
744 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
745 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
746 #stype1, #tfield1, #stype2, #tfield2, \
747 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
748 ret = false; \
749 } \
750 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
751 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
752 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
753 #stype1, #tfield1, #stype2, #tfield2, \
754 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
755 ret = false; \
756 } \
757 s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
758 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
759 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
760 #stype1, #tfield1, #stype2, #tfield2, \
761 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
762 ret = false; \
763 } \
764 s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
765 if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
766 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
767 #stype1, #tfield1, #stype2, #tfield2, \
768 s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
769 ret = false; \
770 }} while (0)
771
772 VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
773 "ALL_INFO", all_info, delete_pending);
774 VAL_CHECK("STANDARD_INFO", standard_info, directory,
775 "ALL_INFO", all_info, directory);
776 VAL_CHECK("STANDARD_INFO", standard_info, nlink,
777 "ALL_INFO", all_info, nlink);
778 s1 = fnum_find("BASIC_INFO");
779 if (s1 && is_ipc) {
780 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
781 printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
782 ret = false;
783 }
784 }
785 s1 = fnum_find("STANDARD_INFO");
786 if (s1 && is_ipc) {
787 if (s1->standard_info.out.nlink != 1) {
788 printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
789 ret = false;
790 }
791 if (s1->standard_info.out.delete_pending != 1) {
792 printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
793 ret = false;
794 }
795 }
796 VAL_CHECK("EA_INFO", ea_info, ea_size,
797 "ALL_INFO", all_info, ea_size);
798 if (!is_ipc) {
799 VAL_CHECK("EA_SIZE", ea_size, ea_size,
800 "ALL_INFO", all_info, ea_size);
801 }
802
803#define NAME_PATH_CHECK(sname, stype, field) do { \
804 s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
805 if (s1 && s2) { \
806 VAL_EQUAL(stype, field, stype, field); \
807 } \
808} while (0)
809
810
811 s1 = fnum_find("INTERNAL_INFORMATION");
812 if (s1) {
813 torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id);
814 }
815
816 NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
817 NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
818 if (s1 && s2) {
819 printf("fnum pos = %.0f, fname pos = %.0f\n",
820 (double)s2->position_information.out.position,
821 (double)s1->position_information.out.position );
822 }
823 NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
824 NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
825 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
826 NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
827
828#if 0
829 /* these are expected to differ */
830 NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
831#endif
832
833#if 0 /* unused */
834#define UNKNOWN_CHECK(sname, stype, tfield) do { \
835 s1 = fnum_find(sname); \
836 if (s1 && s1->stype.out.tfield != 0) { \
837 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
838 #stype, #tfield, \
839 (unsigned int)s1->stype.out.tfield); \
840 } \
841 s1 = fname_find(is_ipc, sname); \
842 if (s1 && s1->stype.out.tfield != 0) { \
843 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
844 #stype, #tfield, \
845 (unsigned int)s1->stype.out.tfield); \
846 }} while (0)
847#endif
848 /* now get a bit fancier .... */
849
850 /* when we set the delete disposition then the link count should drop
851 to 0 and delete_pending should be 1 */
852
853 return ret;
854}
855
856/* basic testing of all RAW_FILEINFO_* calls
857 for each call we test that it succeeds, and where possible test
858 for consistency between the calls.
859*/
860bool torture_raw_qfileinfo(struct torture_context *torture,
861 struct smbcli_state *cli)
862{
863 int fnum;
864 bool ret;
865 const char *fname = "\\torture_qfileinfo.txt";
866
867 fnum = create_complex_file(cli, torture, fname);
868 if (fnum == -1) {
869 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
870 return false;
871 }
872
873 ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */);
874
875 smbcli_close(cli->tree, fnum);
876 smbcli_unlink(cli->tree, fname);
877
878 return ret;
879}
880
881bool torture_raw_qfileinfo_pipe(struct torture_context *torture,
882 struct smbcli_state *cli)
883{
884 bool ret = true;
885 int fnum;
886 const char *fname = "\\lsass";
887 struct dcerpc_pipe *p;
888 struct smbcli_tree *ipc_tree;
889 NTSTATUS status;
890
891 if (!(p = dcerpc_pipe_init(torture, cli->tree->session->transport->socket->event.ctx))) {
892 return false;
893 }
894
895 status = dcerpc_pipe_open_smb(p, cli->tree, fname);
896 torture_assert_ntstatus_ok(torture, status, "dcerpc_pipe_open_smb failed");
897
898 ipc_tree = dcerpc_smb_tree(p->conn);
899 fnum = dcerpc_smb_fnum(p->conn);
900
901 ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, true /* is_ipc */);
902
903 talloc_free(p);
904 return ret;
905}
Note: See TracBrowser for help on using the repository browser.