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 3 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, see <http://www.gnu.org/licenses/>.
21 #include "libcli/libcli.h"
22 #include "torture/util.h"
23 #include "torture/basic/proto.h"
24 #include "torture/raw/proto.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, (unsigned int)s1->n1.out.v1, \
75 #n2, #v2, (unsigned int)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, (unsigned int)s1->n1.out.v1, \
83 #n2, #v2, (unsigned int)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 (unsigned int)s1->n1.out.v1, \
111 (unsigned int)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(struct torture_context
*torture
,
124 struct smbcli_state
*cli
)
129 union smb_fsinfo
*s1
, *s2
;
131 /* scan all the levels, pulling the results */
132 for (i
=0; levels
[i
].name
; i
++) {
133 torture_comment(torture
, "Running level %s\n", levels
[i
].name
);
134 levels
[i
].fsinfo
.generic
.level
= levels
[i
].level
;
135 levels
[i
].status
= smb_raw_fsinfo(cli
->tree
, torture
, &levels
[i
].fsinfo
);
138 /* check for completely broken levels */
139 for (count
=i
=0; levels
[i
].name
; i
++) {
140 uint32_t cap
= cli
->transport
->negotiate
.capabilities
;
141 /* see if this server claims to support this level */
142 if ((cap
& levels
[i
].capability_mask
) != levels
[i
].capability_mask
) {
146 if (!NT_STATUS_IS_OK(levels
[i
].status
)) {
147 printf("ERROR: level %s failed - %s\n",
148 levels
[i
].name
, nt_errstr(levels
[i
].status
));
154 torture_comment(torture
, "%d levels failed\n", count
);
155 torture_assert(torture
, count
> 13, "too many level failures - giving up");
158 torture_comment(torture
, "check for correct aliases\n");
159 s1
= find("SIZE_INFO");
160 s2
= find("SIZE_INFORMATION");
162 VAL_EQUAL(size_info
, total_alloc_units
, size_info
, total_alloc_units
);
163 VAL_APPROX_EQUAL(size_info
, avail_alloc_units
, size_info
, avail_alloc_units
);
164 VAL_EQUAL(size_info
, sectors_per_unit
, size_info
, sectors_per_unit
);
165 VAL_EQUAL(size_info
, bytes_per_sector
, size_info
, bytes_per_sector
);
168 s1
= find("DEVICE_INFO");
169 s2
= find("DEVICE_INFORMATION");
171 VAL_EQUAL(device_info
, device_type
, device_info
, device_type
);
172 VAL_EQUAL(device_info
, characteristics
, device_info
, characteristics
);
175 s1
= find("VOLUME_INFO");
176 s2
= find("VOLUME_INFORMATION");
178 STRUCT_EQUAL(volume_info
, create_time
, volume_info
, create_time
);
179 VAL_EQUAL (volume_info
, serial_number
, volume_info
, serial_number
);
180 STR_EQUAL (volume_info
, volume_name
.s
, volume_info
, volume_name
.s
);
181 torture_comment(torture
, "volume_info.volume_name = '%s'\n", s1
->volume_info
.out
.volume_name
.s
);
184 s1
= find("ATTRIBUTE_INFO");
185 s2
= find("ATTRIBUTE_INFORMATION");
187 VAL_EQUAL(attribute_info
, fs_attr
,
188 attribute_info
, fs_attr
);
189 VAL_EQUAL(attribute_info
, max_file_component_length
,
190 attribute_info
, max_file_component_length
);
191 STR_EQUAL(attribute_info
, fs_type
.s
, attribute_info
, fs_type
.s
);
192 torture_comment(torture
, "attribute_info.fs_type = '%s'\n", s1
->attribute_info
.out
.fs_type
.s
);
195 torture_comment(torture
, "check for consistent disk sizes\n");
196 s1
= find("DSKATTR");
197 s2
= find("ALLOCATION");
200 double scale
= s1
->dskattr
.out
.blocks_per_unit
* s1
->dskattr
.out
.block_size
;
202 s1
->dskattr
.out
.units_total
*
203 s1
->dskattr
.out
.blocks_per_unit
*
204 s1
->dskattr
.out
.block_size
/ scale
;
206 s2
->allocation
.out
.sectors_per_unit
*
207 s2
->allocation
.out
.total_alloc_units
*
208 s2
->allocation
.out
.bytes_per_sector
/ scale
;
209 if (abs(size1
- size2
) > 1) {
210 printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
214 torture_comment(torture
, "total disk = %.0f MB\n", size1
*scale
/1.0e6
);
217 torture_comment(torture
, "check consistent free disk space\n");
218 s1
= find("DSKATTR");
219 s2
= find("ALLOCATION");
222 double scale
= s1
->dskattr
.out
.blocks_per_unit
* s1
->dskattr
.out
.block_size
;
224 s1
->dskattr
.out
.units_free
*
225 s1
->dskattr
.out
.blocks_per_unit
*
226 s1
->dskattr
.out
.block_size
/ scale
;
228 s2
->allocation
.out
.sectors_per_unit
*
229 s2
->allocation
.out
.avail_alloc_units
*
230 s2
->allocation
.out
.bytes_per_sector
/ scale
;
231 if (abs(size1
- size2
) > 1) {
232 printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
236 torture_comment(torture
, "free disk = %.0f MB\n", size1
*scale
/1.0e6
);
239 torture_comment(torture
, "volume info consistency\n");
241 s2
= find("VOLUME_INFO");
243 VAL_EQUAL(volume
, serial_number
, volume_info
, serial_number
);
244 STR_EQUAL(volume
, volume_name
.s
, volume_info
, volume_name
.s
);
247 /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
248 available allocation units, not the total */
249 s1
= find("SIZE_INFO");
250 s2
= find("FULL_SIZE_INFORMATION");
252 VAL_EQUAL(size_info
, total_alloc_units
, full_size_information
, total_alloc_units
);
253 VAL_APPROX_EQUAL(size_info
, avail_alloc_units
, full_size_information
, call_avail_alloc_units
);
254 VAL_EQUAL(size_info
, sectors_per_unit
, full_size_information
, sectors_per_unit
);
255 VAL_EQUAL(size_info
, bytes_per_sector
, full_size_information
, bytes_per_sector
);
258 printf("check for non-zero unknown fields\n");
259 s1
= find("QUOTA_INFORMATION");
261 VAL_UNKNOWN(quota_information
, unknown
[0]);
262 VAL_UNKNOWN(quota_information
, unknown
[1]);
263 VAL_UNKNOWN(quota_information
, unknown
[2]);
266 s1
= find("OBJECTID_INFORMATION");
268 VAL_UNKNOWN(objectid_information
, unknown
[0]);
269 VAL_UNKNOWN(objectid_information
, unknown
[1]);
270 VAL_UNKNOWN(objectid_information
, unknown
[2]);
271 VAL_UNKNOWN(objectid_information
, unknown
[3]);
272 VAL_UNKNOWN(objectid_information
, unknown
[4]);
273 VAL_UNKNOWN(objectid_information
, unknown
[5]);
277 #define STR_CHECK(sname, stype, field, flags) do { \
280 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
281 printf("(%d) incorrect string termination in %s/%s\n", \
282 __LINE__, #stype, #field); \
287 torture_comment(torture
, "check for correct termination\n");
289 STR_CHECK("VOLUME", volume
, volume_name
, 0);
290 STR_CHECK("VOLUME_INFO", volume_info
, volume_name
, STR_UNICODE
);
291 STR_CHECK("VOLUME_INFORMATION", volume_info
, volume_name
, STR_UNICODE
);
292 STR_CHECK("ATTRIBUTE_INFO", attribute_info
, fs_type
, STR_UNICODE
);
293 STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info
, fs_type
, STR_UNICODE
);