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 "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/libcli.h"
24 #include "torture/util.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(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 printf("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 printf("%d levels failed\n", count);
156 printf("too many level failures - giving up\n");
161 printf("check for correct aliases\n");
162 s1 = find("SIZE_INFO");
163 s2 = find("SIZE_INFORMATION");
165 VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
166 VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
167 VAL_EQUAL(size_info, sectors_per_unit, size_info, sectors_per_unit);
168 VAL_EQUAL(size_info, bytes_per_sector, size_info, bytes_per_sector);
171 s1 = find("DEVICE_INFO");
172 s2 = find("DEVICE_INFORMATION");
174 VAL_EQUAL(device_info, device_type, device_info, device_type);
175 VAL_EQUAL(device_info, characteristics, device_info, characteristics);
178 s1 = find("VOLUME_INFO");
179 s2 = find("VOLUME_INFORMATION");
181 STRUCT_EQUAL(volume_info, create_time, volume_info, create_time);
182 VAL_EQUAL (volume_info, serial_number, volume_info, serial_number);
183 STR_EQUAL (volume_info, volume_name.s, volume_info, volume_name.s);
184 printf("volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
187 s1 = find("ATTRIBUTE_INFO");
188 s2 = find("ATTRIBUTE_INFORMATION");
190 VAL_EQUAL(attribute_info, fs_attr,
191 attribute_info, fs_attr);
192 VAL_EQUAL(attribute_info, max_file_component_length,
193 attribute_info, max_file_component_length);
194 STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
195 printf("attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
198 printf("check for consistent disk sizes\n");
199 s1 = find("DSKATTR");
200 s2 = find("ALLOCATION");
203 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
205 s1->dskattr.out.units_total *
206 s1->dskattr.out.blocks_per_unit *
207 s1->dskattr.out.block_size / scale;
209 s2->allocation.out.sectors_per_unit *
210 s2->allocation.out.total_alloc_units *
211 s2->allocation.out.bytes_per_sector / scale;
212 if (abs(size1 - size2) > 1) {
213 printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
217 printf("total disk = %.0f MB\n", size1*scale/1.0e6);
220 printf("check consistent free disk space\n");
221 s1 = find("DSKATTR");
222 s2 = find("ALLOCATION");
225 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
227 s1->dskattr.out.units_free *
228 s1->dskattr.out.blocks_per_unit *
229 s1->dskattr.out.block_size / scale;
231 s2->allocation.out.sectors_per_unit *
232 s2->allocation.out.avail_alloc_units *
233 s2->allocation.out.bytes_per_sector / scale;
234 if (abs(size1 - size2) > 1) {
235 printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
239 printf("free disk = %.0f MB\n", size1*scale/1.0e6);
242 printf("volume info consistency\n");
244 s2 = find("VOLUME_INFO");
246 VAL_EQUAL(volume, serial_number, volume_info, serial_number);
247 STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
250 /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
251 available allocation units, not the total */
252 s1 = find("SIZE_INFO");
253 s2 = find("FULL_SIZE_INFORMATION");
255 VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
256 VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
257 VAL_EQUAL(size_info, sectors_per_unit, full_size_information, sectors_per_unit);
258 VAL_EQUAL(size_info, bytes_per_sector, full_size_information, bytes_per_sector);
261 printf("check for non-zero unknown fields\n");
262 s1 = find("QUOTA_INFORMATION");
264 VAL_UNKNOWN(quota_information, unknown[0]);
265 VAL_UNKNOWN(quota_information, unknown[1]);
266 VAL_UNKNOWN(quota_information, unknown[2]);
269 s1 = find("OBJECTID_INFORMATION");
271 VAL_UNKNOWN(objectid_information, unknown[0]);
272 VAL_UNKNOWN(objectid_information, unknown[1]);
273 VAL_UNKNOWN(objectid_information, unknown[2]);
274 VAL_UNKNOWN(objectid_information, unknown[3]);
275 VAL_UNKNOWN(objectid_information, unknown[4]);
276 VAL_UNKNOWN(objectid_information, unknown[5]);
280 #define STR_CHECK(sname, stype, field, flags) do { \
283 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
284 printf("(%d) incorrect string termination in %s/%s\n", \
285 __LINE__, #stype, #field); \
290 printf("check for correct termination\n");
292 STR_CHECK("VOLUME", volume, volume_name, 0);
293 STR_CHECK("VOLUME_INFO", volume_info, volume_name, STR_UNICODE);
294 STR_CHECK("VOLUME_INFORMATION", volume_info, volume_name, STR_UNICODE);
295 STR_CHECK("ATTRIBUTE_INFO", attribute_info, fs_type, STR_UNICODE);
296 STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);