2 Unix SMB/CIFS implementation.
3 RAW_QFS_* 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.
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
29 enum smb_fsinfo_level level
;
30 uint32_t capability_mask
;
32 union smb_fsinfo fsinfo
;
34 {"DSKATTR", RAW_QFS_DSKATTR
, },
35 {"ALLOCATION", RAW_QFS_ALLOCATION
, },
36 {"VOLUME", RAW_QFS_VOLUME
, },
37 {"VOLUME_INFO", RAW_QFS_VOLUME_INFO
, },
38 {"SIZE_INFO", RAW_QFS_SIZE_INFO
, },
39 {"DEVICE_INFO", RAW_QFS_DEVICE_INFO
, },
40 {"ATTRIBUTE_INFO", RAW_QFS_ATTRIBUTE_INFO
, },
41 {"UNIX_INFO", RAW_QFS_UNIX_INFO
, CAP_UNIX
},
42 {"VOLUME_INFORMATION", RAW_QFS_VOLUME_INFORMATION
, },
43 {"SIZE_INFORMATION", RAW_QFS_SIZE_INFORMATION
, },
44 {"DEVICE_INFORMATION", RAW_QFS_DEVICE_INFORMATION
, },
45 {"ATTRIBUTE_INFORMATION", RAW_QFS_ATTRIBUTE_INFORMATION
, },
46 {"QUOTA_INFORMATION", RAW_QFS_QUOTA_INFORMATION
, },
47 {"FULL_SIZE_INFORMATION", RAW_QFS_FULL_SIZE_INFORMATION
, },
49 /* w2k3 seems to no longer support this */
50 {"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION
, },
57 find a level in the levels[] table
59 static union smb_fsinfo
*find(const char *name
)
62 for (i
=0; levels
[i
].name
; i
++) {
63 if (strcmp(name
, levels
[i
].name
) == 0 &&
64 NT_STATUS_IS_OK(levels
[i
].status
)) {
65 return &levels
[i
].fsinfo
;
71 /* local macros to make the code below more readable */
72 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
73 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
74 #n1, #v1, (uint_t)s1->n1.out.v1, \
75 #n2, #v2, (uint_t)s2->n2.out.v2, \
76 __FILE__, __LINE__); \
80 #define VAL_APPROX_EQUAL(n1, v1, n2, v2) do {if (ABS((int)(s1->n1.out.v1) - (int)(s2->n2.out.v2)) > 0.1*s1->n1.out.v1) { \
81 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
82 #n1, #v1, (uint_t)s1->n1.out.v1, \
83 #n2, #v2, (uint_t)s2->n2.out.v2, \
84 __FILE__, __LINE__); \
88 #define STR_EQUAL(n1, v1, n2, v2) do { \
89 if (strcmp_safe(s1->n1.out.v1, s2->n2.out.v2)) { \
90 printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
91 #n1, #v1, s1->n1.out.v1, \
92 #n2, #v2, s2->n2.out.v2, \
93 __FILE__, __LINE__); \
97 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
98 printf("%s/%s != %s/%s at %s(%d)\n", \
101 __FILE__, __LINE__); \
105 /* used to find hints on unknown values - and to make sure
107 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
108 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
110 (uint_t)s1->n1.out.v1, \
111 (uint_t)s1->n1.out.v1, \
112 __FILE__, __LINE__); \
116 /* basic testing of all RAW_QFS_* calls
117 for each call we test that it succeeds, and where possible test
118 for consistency between the calls.
120 Some of the consistency tests assume that the target filesystem is
121 quiescent, which is sometimes hard to achieve
123 BOOL
torture_raw_qfsinfo(void)
125 struct smbcli_state
*cli
;
129 union smb_fsinfo
*s1
, *s2
;
132 if (!torture_open_connection(&cli
)) {
136 mem_ctx
= talloc_init("torture_qfsinfo");
138 /* scan all the levels, pulling the results */
139 for (i
=0; levels
[i
].name
; i
++) {
140 printf("Running level %s\n", levels
[i
].name
);
141 levels
[i
].fsinfo
.generic
.level
= levels
[i
].level
;
142 levels
[i
].status
= smb_raw_fsinfo(cli
->tree
, mem_ctx
, &levels
[i
].fsinfo
);
145 /* check for completely broken levels */
146 for (count
=i
=0; levels
[i
].name
; i
++) {
147 uint32_t cap
= cli
->transport
->negotiate
.capabilities
;
148 /* see if this server claims to support this level */
149 if ((cap
& levels
[i
].capability_mask
) != levels
[i
].capability_mask
) {
153 if (!NT_STATUS_IS_OK(levels
[i
].status
)) {
154 printf("ERROR: level %s failed - %s\n",
155 levels
[i
].name
, nt_errstr(levels
[i
].status
));
162 printf("%d levels failed\n", count
);
164 printf("too many level failures - giving up\n");
169 printf("check for correct aliases\n");
170 s1
= find("SIZE_INFO");
171 s2
= find("SIZE_INFORMATION");
173 VAL_EQUAL(size_info
, total_alloc_units
, size_info
, total_alloc_units
);
174 VAL_APPROX_EQUAL(size_info
, avail_alloc_units
, size_info
, avail_alloc_units
);
175 VAL_EQUAL(size_info
, sectors_per_unit
, size_info
, sectors_per_unit
);
176 VAL_EQUAL(size_info
, bytes_per_sector
, size_info
, bytes_per_sector
);
179 s1
= find("DEVICE_INFO");
180 s2
= find("DEVICE_INFORMATION");
182 VAL_EQUAL(device_info
, device_type
, device_info
, device_type
);
183 VAL_EQUAL(device_info
, characteristics
, device_info
, characteristics
);
186 s1
= find("VOLUME_INFO");
187 s2
= find("VOLUME_INFORMATION");
189 STRUCT_EQUAL(volume_info
, create_time
, volume_info
, create_time
);
190 VAL_EQUAL (volume_info
, serial_number
, volume_info
, serial_number
);
191 STR_EQUAL (volume_info
, volume_name
.s
, volume_info
, volume_name
.s
);
192 printf("volume_info.volume_name = '%s'\n", s1
->volume_info
.out
.volume_name
.s
);
195 s1
= find("ATTRIBUTE_INFO");
196 s2
= find("ATTRIBUTE_INFORMATION");
198 VAL_EQUAL(attribute_info
, fs_attr
,
199 attribute_info
, fs_attr
);
200 VAL_EQUAL(attribute_info
, max_file_component_length
,
201 attribute_info
, max_file_component_length
);
202 STR_EQUAL(attribute_info
, fs_type
.s
, attribute_info
, fs_type
.s
);
203 printf("attribute_info.fs_type = '%s'\n", s1
->attribute_info
.out
.fs_type
.s
);
206 printf("check for consistent disk sizes\n");
207 s1
= find("DSKATTR");
208 s2
= find("ALLOCATION");
211 double scale
= s1
->dskattr
.out
.blocks_per_unit
* s1
->dskattr
.out
.block_size
;
213 s1
->dskattr
.out
.units_total
*
214 s1
->dskattr
.out
.blocks_per_unit
*
215 s1
->dskattr
.out
.block_size
/ scale
;
217 s2
->allocation
.out
.sectors_per_unit
*
218 s2
->allocation
.out
.total_alloc_units
*
219 s2
->allocation
.out
.bytes_per_sector
/ scale
;
220 if (ABS(size1
- size2
) > 1) {
221 printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
225 printf("total disk = %.0f MB\n", size1
*scale
/1.0e6
);
228 printf("check consistent free disk space\n");
229 s1
= find("DSKATTR");
230 s2
= find("ALLOCATION");
233 double scale
= s1
->dskattr
.out
.blocks_per_unit
* s1
->dskattr
.out
.block_size
;
235 s1
->dskattr
.out
.units_free
*
236 s1
->dskattr
.out
.blocks_per_unit
*
237 s1
->dskattr
.out
.block_size
/ scale
;
239 s2
->allocation
.out
.sectors_per_unit
*
240 s2
->allocation
.out
.avail_alloc_units
*
241 s2
->allocation
.out
.bytes_per_sector
/ scale
;
242 if (ABS(size1
- size2
) > 1) {
243 printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
247 printf("free disk = %.0f MB\n", size1
*scale
/1.0e6
);
250 printf("volume info consistency\n");
252 s2
= find("VOLUME_INFO");
254 VAL_EQUAL(volume
, serial_number
, volume_info
, serial_number
);
255 STR_EQUAL(volume
, volume_name
.s
, volume_info
, volume_name
.s
);
258 /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
259 available allocation units, not the total */
260 s1
= find("SIZE_INFO");
261 s2
= find("FULL_SIZE_INFORMATION");
263 VAL_EQUAL(size_info
, total_alloc_units
, full_size_information
, total_alloc_units
);
264 VAL_APPROX_EQUAL(size_info
, avail_alloc_units
, full_size_information
, call_avail_alloc_units
);
265 VAL_EQUAL(size_info
, sectors_per_unit
, full_size_information
, sectors_per_unit
);
266 VAL_EQUAL(size_info
, bytes_per_sector
, full_size_information
, bytes_per_sector
);
269 printf("check for non-zero unknown fields\n");
270 s1
= find("QUOTA_INFORMATION");
272 VAL_UNKNOWN(quota_information
, unknown
[0]);
273 VAL_UNKNOWN(quota_information
, unknown
[1]);
274 VAL_UNKNOWN(quota_information
, unknown
[2]);
277 s1
= find("OBJECTID_INFORMATION");
279 VAL_UNKNOWN(objectid_information
, unknown
[0]);
280 VAL_UNKNOWN(objectid_information
, unknown
[1]);
281 VAL_UNKNOWN(objectid_information
, unknown
[2]);
282 VAL_UNKNOWN(objectid_information
, unknown
[3]);
283 VAL_UNKNOWN(objectid_information
, unknown
[4]);
284 VAL_UNKNOWN(objectid_information
, unknown
[5]);
288 #define STR_CHECK(sname, stype, field, flags) do { \
291 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli)) { \
292 printf("(%d) incorrect string termination in %s/%s\n", \
293 __LINE__, #stype, #field); \
298 printf("check for correct termination\n");
300 STR_CHECK("VOLUME", volume
, volume_name
, 0);
301 STR_CHECK("VOLUME_INFO", volume_info
, volume_name
, STR_UNICODE
);
302 STR_CHECK("VOLUME_INFORMATION", volume_info
, volume_name
, STR_UNICODE
);
303 STR_CHECK("ATTRIBUTE_INFO", attribute_info
, fs_type
, STR_UNICODE
);
304 STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info
, fs_type
, STR_UNICODE
);
307 torture_close_connection(cli
);
308 talloc_free(mem_ctx
);