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"
27 enum smb_fsinfo_level level
;
28 uint32_t capability_mask
;
30 union smb_fsinfo fsinfo
;
32 {"DSKATTR", RAW_QFS_DSKATTR
, },
33 {"ALLOCATION", RAW_QFS_ALLOCATION
, },
34 {"VOLUME", RAW_QFS_VOLUME
, },
35 {"VOLUME_INFO", RAW_QFS_VOLUME_INFO
, },
36 {"SIZE_INFO", RAW_QFS_SIZE_INFO
, },
37 {"DEVICE_INFO", RAW_QFS_DEVICE_INFO
, },
38 {"ATTRIBUTE_INFO", RAW_QFS_ATTRIBUTE_INFO
, },
39 {"UNIX_INFO", RAW_QFS_UNIX_INFO
, CAP_UNIX
},
40 {"VOLUME_INFORMATION", RAW_QFS_VOLUME_INFORMATION
, },
41 {"SIZE_INFORMATION", RAW_QFS_SIZE_INFORMATION
, },
42 {"DEVICE_INFORMATION", RAW_QFS_DEVICE_INFORMATION
, },
43 {"ATTRIBUTE_INFORMATION", RAW_QFS_ATTRIBUTE_INFORMATION
, },
44 {"QUOTA_INFORMATION", RAW_QFS_QUOTA_INFORMATION
, },
45 {"FULL_SIZE_INFORMATION", RAW_QFS_FULL_SIZE_INFORMATION
, },
47 /* w2k3 seems to no longer support this */
48 {"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION
, },
55 find a level in the levels[] table
57 static union smb_fsinfo
*find(const char *name
)
60 for (i
=0; levels
[i
].name
; i
++) {
61 if (strcmp(name
, levels
[i
].name
) == 0 &&
62 NT_STATUS_IS_OK(levels
[i
].status
)) {
63 return &levels
[i
].fsinfo
;
69 /* local macros to make the code below more readable */
70 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
71 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
72 #n1, #v1, (unsigned int)s1->n1.out.v1, \
73 #n2, #v2, (unsigned int)s2->n2.out.v2, \
74 __FILE__, __LINE__); \
78 #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) { \
79 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
80 #n1, #v1, (unsigned int)s1->n1.out.v1, \
81 #n2, #v2, (unsigned int)s2->n2.out.v2, \
82 __FILE__, __LINE__); \
86 #define STR_EQUAL(n1, v1, n2, v2) do { \
87 if (strcmp_safe(s1->n1.out.v1, s2->n2.out.v2)) { \
88 printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
89 #n1, #v1, s1->n1.out.v1, \
90 #n2, #v2, s2->n2.out.v2, \
91 __FILE__, __LINE__); \
95 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
96 printf("%s/%s != %s/%s at %s(%d)\n", \
99 __FILE__, __LINE__); \
103 /* used to find hints on unknown values - and to make sure
105 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
106 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
108 (unsigned int)s1->n1.out.v1, \
109 (unsigned int)s1->n1.out.v1, \
110 __FILE__, __LINE__); \
114 /* basic testing of all RAW_QFS_* calls
115 for each call we test that it succeeds, and where possible test
116 for consistency between the calls.
118 Some of the consistency tests assume that the target filesystem is
119 quiescent, which is sometimes hard to achieve
121 bool torture_raw_qfsinfo(struct torture_context
*torture
,
122 struct smbcli_state
*cli
)
127 union smb_fsinfo
*s1
, *s2
;
129 /* scan all the levels, pulling the results */
130 for (i
=0; levels
[i
].name
; i
++) {
131 torture_comment(torture
, "Running level %s\n", levels
[i
].name
);
132 levels
[i
].fsinfo
.generic
.level
= levels
[i
].level
;
133 levels
[i
].status
= smb_raw_fsinfo(cli
->tree
, torture
, &levels
[i
].fsinfo
);
136 /* check for completely broken levels */
137 for (count
=i
=0; levels
[i
].name
; i
++) {
138 uint32_t cap
= cli
->transport
->negotiate
.capabilities
;
139 /* see if this server claims to support this level */
140 if ((cap
& levels
[i
].capability_mask
) != levels
[i
].capability_mask
) {
144 if (!NT_STATUS_IS_OK(levels
[i
].status
)) {
145 printf("ERROR: level %s failed - %s\n",
146 levels
[i
].name
, nt_errstr(levels
[i
].status
));
152 torture_comment(torture
, "%d levels failed\n", count
);
153 torture_assert(torture
, count
> 13, "too many level failures - giving up");
156 torture_comment(torture
, "check for correct aliases\n");
157 s1
= find("SIZE_INFO");
158 s2
= find("SIZE_INFORMATION");
160 VAL_EQUAL(size_info
, total_alloc_units
, size_info
, total_alloc_units
);
161 VAL_APPROX_EQUAL(size_info
, avail_alloc_units
, size_info
, avail_alloc_units
);
162 VAL_EQUAL(size_info
, sectors_per_unit
, size_info
, sectors_per_unit
);
163 VAL_EQUAL(size_info
, bytes_per_sector
, size_info
, bytes_per_sector
);
166 s1
= find("DEVICE_INFO");
167 s2
= find("DEVICE_INFORMATION");
169 VAL_EQUAL(device_info
, device_type
, device_info
, device_type
);
170 VAL_EQUAL(device_info
, characteristics
, device_info
, characteristics
);
173 s1
= find("VOLUME_INFO");
174 s2
= find("VOLUME_INFORMATION");
176 STRUCT_EQUAL(volume_info
, create_time
, volume_info
, create_time
);
177 VAL_EQUAL (volume_info
, serial_number
, volume_info
, serial_number
);
178 STR_EQUAL (volume_info
, volume_name
.s
, volume_info
, volume_name
.s
);
179 torture_comment(torture
, "volume_info.volume_name = '%s'\n", s1
->volume_info
.out
.volume_name
.s
);
182 s1
= find("ATTRIBUTE_INFO");
183 s2
= find("ATTRIBUTE_INFORMATION");
185 VAL_EQUAL(attribute_info
, fs_attr
,
186 attribute_info
, fs_attr
);
187 VAL_EQUAL(attribute_info
, max_file_component_length
,
188 attribute_info
, max_file_component_length
);
189 STR_EQUAL(attribute_info
, fs_type
.s
, attribute_info
, fs_type
.s
);
190 torture_comment(torture
, "attribute_info.fs_type = '%s'\n", s1
->attribute_info
.out
.fs_type
.s
);
193 torture_comment(torture
, "check for consistent disk sizes\n");
194 s1
= find("DSKATTR");
195 s2
= find("ALLOCATION");
198 double scale
= s1
->dskattr
.out
.blocks_per_unit
* s1
->dskattr
.out
.block_size
;
200 s1
->dskattr
.out
.units_total
*
201 s1
->dskattr
.out
.blocks_per_unit
*
202 s1
->dskattr
.out
.block_size
/ scale
;
204 s2
->allocation
.out
.sectors_per_unit
*
205 s2
->allocation
.out
.total_alloc_units
*
206 s2
->allocation
.out
.bytes_per_sector
/ scale
;
207 if (abs(size1
- size2
) > 1) {
208 printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
212 torture_comment(torture
, "total disk = %.0f MB\n", size1
*scale
/1.0e6
);
215 torture_comment(torture
, "check consistent free disk space\n");
216 s1
= find("DSKATTR");
217 s2
= find("ALLOCATION");
220 double scale
= s1
->dskattr
.out
.blocks_per_unit
* s1
->dskattr
.out
.block_size
;
222 s1
->dskattr
.out
.units_free
*
223 s1
->dskattr
.out
.blocks_per_unit
*
224 s1
->dskattr
.out
.block_size
/ scale
;
226 s2
->allocation
.out
.sectors_per_unit
*
227 s2
->allocation
.out
.avail_alloc_units
*
228 s2
->allocation
.out
.bytes_per_sector
/ scale
;
229 if (abs(size1
- size2
) > 1) {
230 printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
234 torture_comment(torture
, "free disk = %.0f MB\n", size1
*scale
/1.0e6
);
237 torture_comment(torture
, "volume info consistency\n");
239 s2
= find("VOLUME_INFO");
241 VAL_EQUAL(volume
, serial_number
, volume_info
, serial_number
);
242 STR_EQUAL(volume
, volume_name
.s
, volume_info
, volume_name
.s
);
245 /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
246 available allocation units, not the total */
247 s1
= find("SIZE_INFO");
248 s2
= find("FULL_SIZE_INFORMATION");
250 VAL_EQUAL(size_info
, total_alloc_units
, full_size_information
, total_alloc_units
);
251 VAL_APPROX_EQUAL(size_info
, avail_alloc_units
, full_size_information
, call_avail_alloc_units
);
252 VAL_EQUAL(size_info
, sectors_per_unit
, full_size_information
, sectors_per_unit
);
253 VAL_EQUAL(size_info
, bytes_per_sector
, full_size_information
, bytes_per_sector
);
256 printf("check for non-zero unknown fields\n");
257 s1
= find("QUOTA_INFORMATION");
259 VAL_UNKNOWN(quota_information
, unknown
[0]);
260 VAL_UNKNOWN(quota_information
, unknown
[1]);
261 VAL_UNKNOWN(quota_information
, unknown
[2]);
264 s1
= find("OBJECTID_INFORMATION");
266 VAL_UNKNOWN(objectid_information
, unknown
[0]);
267 VAL_UNKNOWN(objectid_information
, unknown
[1]);
268 VAL_UNKNOWN(objectid_information
, unknown
[2]);
269 VAL_UNKNOWN(objectid_information
, unknown
[3]);
270 VAL_UNKNOWN(objectid_information
, unknown
[4]);
271 VAL_UNKNOWN(objectid_information
, unknown
[5]);
275 #define STR_CHECK(sname, stype, field, flags) do { \
278 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
279 printf("(%d) incorrect string termination in %s/%s\n", \
280 __LINE__, #stype, #field); \
285 torture_comment(torture
, "check for correct termination\n");
287 STR_CHECK("VOLUME", volume
, volume_name
, 0);
288 STR_CHECK("VOLUME_INFO", volume_info
, volume_name
, STR_UNICODE
);
289 STR_CHECK("VOLUME_INFORMATION", volume_info
, volume_name
, STR_UNICODE
);
290 STR_CHECK("ATTRIBUTE_INFO", attribute_info
, fs_type
, STR_UNICODE
);
291 STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info
, fs_type
, STR_UNICODE
);