r22838: Add in an explority test for what QFSINFO operations are valid on IPC$
[Samba.git] / source / torture / raw / qfsinfo.c
blob50a5a6609a3524a49869a1b908d63202b2aee0a7
1 /*
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.
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "torture/util.h"
28 static struct {
29 const char *name;
30 enum smb_fsinfo_level level;
31 uint32_t capability_mask;
32 NTSTATUS status;
33 union smb_fsinfo fsinfo;
34 } levels[] = {
35 {"DSKATTR", RAW_QFS_DSKATTR, },
36 {"ALLOCATION", RAW_QFS_ALLOCATION, },
37 {"VOLUME", RAW_QFS_VOLUME, },
38 {"VOLUME_INFO", RAW_QFS_VOLUME_INFO, },
39 {"SIZE_INFO", RAW_QFS_SIZE_INFO, },
40 {"DEVICE_INFO", RAW_QFS_DEVICE_INFO, },
41 {"ATTRIBUTE_INFO", RAW_QFS_ATTRIBUTE_INFO, },
42 {"UNIX_INFO", RAW_QFS_UNIX_INFO, CAP_UNIX},
43 {"VOLUME_INFORMATION", RAW_QFS_VOLUME_INFORMATION, },
44 {"SIZE_INFORMATION", RAW_QFS_SIZE_INFORMATION, },
45 {"DEVICE_INFORMATION", RAW_QFS_DEVICE_INFORMATION, },
46 {"ATTRIBUTE_INFORMATION", RAW_QFS_ATTRIBUTE_INFORMATION, },
47 {"QUOTA_INFORMATION", RAW_QFS_QUOTA_INFORMATION, },
48 {"FULL_SIZE_INFORMATION", RAW_QFS_FULL_SIZE_INFORMATION, },
49 #if 0
50 /* w2k3 seems to no longer support this */
51 {"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION, },
52 #endif
53 { NULL, }
58 find a level in the levels[] table
60 static union smb_fsinfo *find(const char *name)
62 int i;
63 for (i=0; levels[i].name; i++) {
64 if (strcmp(name, levels[i].name) == 0 &&
65 NT_STATUS_IS_OK(levels[i].status)) {
66 return &levels[i].fsinfo;
69 return NULL;
72 /* local macros to make the code below more readable */
73 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
74 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
75 #n1, #v1, (uint_t)s1->n1.out.v1, \
76 #n2, #v2, (uint_t)s2->n2.out.v2, \
77 __FILE__, __LINE__); \
78 ret = False; \
79 }} while(0)
81 #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) { \
82 printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
83 #n1, #v1, (uint_t)s1->n1.out.v1, \
84 #n2, #v2, (uint_t)s2->n2.out.v2, \
85 __FILE__, __LINE__); \
86 ret = False; \
87 }} while(0)
89 #define STR_EQUAL(n1, v1, n2, v2) do { \
90 if (strcmp_safe(s1->n1.out.v1, s2->n2.out.v2)) { \
91 printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
92 #n1, #v1, s1->n1.out.v1, \
93 #n2, #v2, s2->n2.out.v2, \
94 __FILE__, __LINE__); \
95 ret = False; \
96 }} while(0)
98 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
99 printf("%s/%s != %s/%s at %s(%d)\n", \
100 #n1, #v1, \
101 #n2, #v2, \
102 __FILE__, __LINE__); \
103 ret = False; \
104 }} while(0)
106 /* used to find hints on unknown values - and to make sure
107 we zero-fill */
108 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
109 printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
110 #n1, #v1, \
111 (uint_t)s1->n1.out.v1, \
112 (uint_t)s1->n1.out.v1, \
113 __FILE__, __LINE__); \
114 ret = False; \
115 }} while(0)
117 /* basic testing of all RAW_QFS_* calls
118 for each call we test that it succeeds, and where possible test
119 for consistency between the calls.
121 Some of the consistency tests assume that the target filesystem is
122 quiescent, which is sometimes hard to achieve
124 BOOL torture_raw_qfsinfo(struct torture_context *torture)
126 struct smbcli_state *cli;
127 int i;
128 BOOL ret = True;
129 int count;
130 union smb_fsinfo *s1, *s2;
131 TALLOC_CTX *mem_ctx;
133 if (!torture_open_connection(&cli, 0)) {
134 return False;
137 mem_ctx = talloc_init("torture_qfsinfo");
139 /* scan all the levels, pulling the results */
140 for (i=0; levels[i].name; i++) {
141 printf("Running level %s\n", levels[i].name);
142 levels[i].fsinfo.generic.level = levels[i].level;
143 levels[i].status = smb_raw_fsinfo(cli->tree, mem_ctx, &levels[i].fsinfo);
146 /* check for completely broken levels */
147 for (count=i=0; levels[i].name; i++) {
148 uint32_t cap = cli->transport->negotiate.capabilities;
149 /* see if this server claims to support this level */
150 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
151 continue;
154 if (!NT_STATUS_IS_OK(levels[i].status)) {
155 printf("ERROR: level %s failed - %s\n",
156 levels[i].name, nt_errstr(levels[i].status));
157 count++;
161 if (count != 0) {
162 ret = False;
163 printf("%d levels failed\n", count);
164 if (count > 13) {
165 printf("too many level failures - giving up\n");
166 goto done;
170 printf("check for correct aliases\n");
171 s1 = find("SIZE_INFO");
172 s2 = find("SIZE_INFORMATION");
173 if (s1 && s2) {
174 VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
175 VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
176 VAL_EQUAL(size_info, sectors_per_unit, size_info, sectors_per_unit);
177 VAL_EQUAL(size_info, bytes_per_sector, size_info, bytes_per_sector);
180 s1 = find("DEVICE_INFO");
181 s2 = find("DEVICE_INFORMATION");
182 if (s1 && s2) {
183 VAL_EQUAL(device_info, device_type, device_info, device_type);
184 VAL_EQUAL(device_info, characteristics, device_info, characteristics);
187 s1 = find("VOLUME_INFO");
188 s2 = find("VOLUME_INFORMATION");
189 if (s1 && s2) {
190 STRUCT_EQUAL(volume_info, create_time, volume_info, create_time);
191 VAL_EQUAL (volume_info, serial_number, volume_info, serial_number);
192 STR_EQUAL (volume_info, volume_name.s, volume_info, volume_name.s);
193 printf("volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
196 s1 = find("ATTRIBUTE_INFO");
197 s2 = find("ATTRIBUTE_INFORMATION");
198 if (s1 && s2) {
199 VAL_EQUAL(attribute_info, fs_attr,
200 attribute_info, fs_attr);
201 VAL_EQUAL(attribute_info, max_file_component_length,
202 attribute_info, max_file_component_length);
203 STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
204 printf("attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
207 printf("check for consistent disk sizes\n");
208 s1 = find("DSKATTR");
209 s2 = find("ALLOCATION");
210 if (s1 && s2) {
211 double size1, size2;
212 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
213 size1 = 1.0 *
214 s1->dskattr.out.units_total *
215 s1->dskattr.out.blocks_per_unit *
216 s1->dskattr.out.block_size / scale;
217 size2 = 1.0 *
218 s2->allocation.out.sectors_per_unit *
219 s2->allocation.out.total_alloc_units *
220 s2->allocation.out.bytes_per_sector / scale;
221 if (abs(size1 - size2) > 1) {
222 printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
223 size1, size2);
224 ret = False;
226 printf("total disk = %.0f MB\n", size1*scale/1.0e6);
229 printf("check consistent free disk space\n");
230 s1 = find("DSKATTR");
231 s2 = find("ALLOCATION");
232 if (s1 && s2) {
233 double size1, size2;
234 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
235 size1 = 1.0 *
236 s1->dskattr.out.units_free *
237 s1->dskattr.out.blocks_per_unit *
238 s1->dskattr.out.block_size / scale;
239 size2 = 1.0 *
240 s2->allocation.out.sectors_per_unit *
241 s2->allocation.out.avail_alloc_units *
242 s2->allocation.out.bytes_per_sector / scale;
243 if (abs(size1 - size2) > 1) {
244 printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
245 size1, size2);
246 ret = False;
248 printf("free disk = %.0f MB\n", size1*scale/1.0e6);
251 printf("volume info consistency\n");
252 s1 = find("VOLUME");
253 s2 = find("VOLUME_INFO");
254 if (s1 && s2) {
255 VAL_EQUAL(volume, serial_number, volume_info, serial_number);
256 STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
259 /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
260 available allocation units, not the total */
261 s1 = find("SIZE_INFO");
262 s2 = find("FULL_SIZE_INFORMATION");
263 if (s1 && s2) {
264 VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
265 VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
266 VAL_EQUAL(size_info, sectors_per_unit, full_size_information, sectors_per_unit);
267 VAL_EQUAL(size_info, bytes_per_sector, full_size_information, bytes_per_sector);
270 printf("check for non-zero unknown fields\n");
271 s1 = find("QUOTA_INFORMATION");
272 if (s1) {
273 VAL_UNKNOWN(quota_information, unknown[0]);
274 VAL_UNKNOWN(quota_information, unknown[1]);
275 VAL_UNKNOWN(quota_information, unknown[2]);
278 s1 = find("OBJECTID_INFORMATION");
279 if (s1) {
280 VAL_UNKNOWN(objectid_information, unknown[0]);
281 VAL_UNKNOWN(objectid_information, unknown[1]);
282 VAL_UNKNOWN(objectid_information, unknown[2]);
283 VAL_UNKNOWN(objectid_information, unknown[3]);
284 VAL_UNKNOWN(objectid_information, unknown[4]);
285 VAL_UNKNOWN(objectid_information, unknown[5]);
289 #define STR_CHECK(sname, stype, field, flags) do { \
290 s1 = find(sname); \
291 if (s1) { \
292 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
293 printf("(%d) incorrect string termination in %s/%s\n", \
294 __LINE__, #stype, #field); \
295 ret = False; \
297 }} while (0)
299 printf("check for correct termination\n");
301 STR_CHECK("VOLUME", volume, volume_name, 0);
302 STR_CHECK("VOLUME_INFO", volume_info, volume_name, STR_UNICODE);
303 STR_CHECK("VOLUME_INFORMATION", volume_info, volume_name, STR_UNICODE);
304 STR_CHECK("ATTRIBUTE_INFO", attribute_info, fs_type, STR_UNICODE);
305 STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);
307 done:
308 torture_close_connection(cli);
309 talloc_free(mem_ctx);
310 return ret;