source: trunk/server/source4/torture/raw/qfsinfo.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: 10.4 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 RAW_QFS_* individual test suite
4 Copyright (C) Andrew Tridgell 2003
5
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.
10
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.
15
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/>.
18*/
19
20#include "includes.h"
21#include "libcli/libcli.h"
22#include "torture/util.h"
23
24
25static struct {
26 const char *name;
27 enum smb_fsinfo_level level;
28 uint32_t capability_mask;
29 NTSTATUS status;
30 union smb_fsinfo fsinfo;
31} levels[] = {
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, },
46#if 0
47 /* w2k3 seems to no longer support this */
48 {"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION, },
49#endif
50 { NULL, }
51};
52
53
54/*
55 find a level in the levels[] table
56*/
57static union smb_fsinfo *find(const char *name)
58{
59 int i;
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;
64 }
65 }
66 return NULL;
67}
68
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__); \
75 ret = false; \
76}} while(0)
77
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__); \
83 ret = false; \
84}} while(0)
85
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__); \
92 ret = false; \
93}} while(0)
94
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", \
97 #n1, #v1, \
98 #n2, #v2, \
99 __FILE__, __LINE__); \
100 ret = false; \
101}} while(0)
102
103/* used to find hints on unknown values - and to make sure
104 we zero-fill */
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", \
107 #n1, #v1, \
108 (unsigned int)s1->n1.out.v1, \
109 (unsigned int)s1->n1.out.v1, \
110 __FILE__, __LINE__); \
111 ret = false; \
112}} while(0)
113
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.
117
118 Some of the consistency tests assume that the target filesystem is
119 quiescent, which is sometimes hard to achieve
120*/
121bool torture_raw_qfsinfo(struct torture_context *torture,
122 struct smbcli_state *cli)
123{
124 int i;
125 bool ret = true;
126 int count;
127 union smb_fsinfo *s1, *s2;
128
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);
134 }
135
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) {
141 continue;
142 }
143
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));
147 count++;
148 }
149 }
150
151 if (count != 0) {
152 torture_comment(torture, "%d levels failed\n", count);
153 torture_assert(torture, count > 13, "too many level failures - giving up");
154 }
155
156 torture_comment(torture, "check for correct aliases\n");
157 s1 = find("SIZE_INFO");
158 s2 = find("SIZE_INFORMATION");
159 if (s1 && s2) {
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);
164 }
165
166 s1 = find("DEVICE_INFO");
167 s2 = find("DEVICE_INFORMATION");
168 if (s1 && s2) {
169 VAL_EQUAL(device_info, device_type, device_info, device_type);
170 VAL_EQUAL(device_info, characteristics, device_info, characteristics);
171 }
172
173 s1 = find("VOLUME_INFO");
174 s2 = find("VOLUME_INFORMATION");
175 if (s1 && s2) {
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);
180 }
181
182 s1 = find("ATTRIBUTE_INFO");
183 s2 = find("ATTRIBUTE_INFORMATION");
184 if (s1 && s2) {
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);
191 }
192
193 torture_comment(torture, "check for consistent disk sizes\n");
194 s1 = find("DSKATTR");
195 s2 = find("ALLOCATION");
196 if (s1 && s2) {
197 double size1, size2;
198 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
199 size1 = 1.0 *
200 s1->dskattr.out.units_total *
201 s1->dskattr.out.blocks_per_unit *
202 s1->dskattr.out.block_size / scale;
203 size2 = 1.0 *
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",
209 size1, size2);
210 ret = false;
211 }
212 torture_comment(torture, "total disk = %.0f MB\n", size1*scale/1.0e6);
213 }
214
215 torture_comment(torture, "check consistent free disk space\n");
216 s1 = find("DSKATTR");
217 s2 = find("ALLOCATION");
218 if (s1 && s2) {
219 double size1, size2;
220 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
221 size1 = 1.0 *
222 s1->dskattr.out.units_free *
223 s1->dskattr.out.blocks_per_unit *
224 s1->dskattr.out.block_size / scale;
225 size2 = 1.0 *
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",
231 size1, size2);
232 ret = false;
233 }
234 torture_comment(torture, "free disk = %.0f MB\n", size1*scale/1.0e6);
235 }
236
237 torture_comment(torture, "volume info consistency\n");
238 s1 = find("VOLUME");
239 s2 = find("VOLUME_INFO");
240 if (s1 && s2) {
241 VAL_EQUAL(volume, serial_number, volume_info, serial_number);
242 STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
243 }
244
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");
249 if (s1 && s2) {
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);
254 }
255
256 printf("check for non-zero unknown fields\n");
257 s1 = find("QUOTA_INFORMATION");
258 if (s1) {
259 VAL_UNKNOWN(quota_information, unknown[0]);
260 VAL_UNKNOWN(quota_information, unknown[1]);
261 VAL_UNKNOWN(quota_information, unknown[2]);
262 }
263
264 s1 = find("OBJECTID_INFORMATION");
265 if (s1) {
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]);
272 }
273
274
275#define STR_CHECK(sname, stype, field, flags) do { \
276 s1 = find(sname); \
277 if (s1) { \
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); \
281 ret = false; \
282 } \
283 }} while (0)
284
285 torture_comment(torture, "check for correct termination\n");
286
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);
292
293 return ret;
294}
Note: See TracBrowser for help on using the repository browser.