r13121: Tag 4.0.0TP1
[Samba.git] / source / torture / raw / qfsinfo.c
blob26bac4c0ad0431216a6fa8c7d897783c775cf903
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"
27 static struct {
28 const char *name;
29 enum smb_fsinfo_level level;
30 uint32_t capability_mask;
31 NTSTATUS status;
32 union smb_fsinfo fsinfo;
33 } levels[] = {
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, },
48 #if 0
49 /* w2k3 seems to no longer support this */
50 {"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION, },
51 #endif
52 { NULL, }
57 find a level in the levels[] table
59 static union smb_fsinfo *find(const char *name)
61 int i;
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;
68 return NULL;
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__); \
77 ret = False; \
78 }} while(0)
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__); \
85 ret = False; \
86 }} while(0)
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__); \
94 ret = False; \
95 }} while(0)
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", \
99 #n1, #v1, \
100 #n2, #v2, \
101 __FILE__, __LINE__); \
102 ret = False; \
103 }} while(0)
105 /* used to find hints on unknown values - and to make sure
106 we zero-fill */
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", \
109 #n1, #v1, \
110 (uint_t)s1->n1.out.v1, \
111 (uint_t)s1->n1.out.v1, \
112 __FILE__, __LINE__); \
113 ret = False; \
114 }} while(0)
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(void)
125 struct smbcli_state *cli;
126 int i;
127 BOOL ret = True;
128 int count;
129 union smb_fsinfo *s1, *s2;
130 TALLOC_CTX *mem_ctx;
132 if (!torture_open_connection(&cli)) {
133 return False;
136 mem_ctx = talloc_init("torture_qfsinfo");
138 /* scan all the levels, pulling the results */
139 for (i=0; levels[i].name; i++) {
140 printf("Running level %s\n", levels[i].name);
141 levels[i].fsinfo.generic.level = levels[i].level;
142 levels[i].status = smb_raw_fsinfo(cli->tree, mem_ctx, &levels[i].fsinfo);
145 /* check for completely broken levels */
146 for (count=i=0; levels[i].name; i++) {
147 uint32_t cap = cli->transport->negotiate.capabilities;
148 /* see if this server claims to support this level */
149 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
150 continue;
153 if (!NT_STATUS_IS_OK(levels[i].status)) {
154 printf("ERROR: level %s failed - %s\n",
155 levels[i].name, nt_errstr(levels[i].status));
156 count++;
160 if (count != 0) {
161 ret = False;
162 printf("%d levels failed\n", count);
163 if (count > 13) {
164 printf("too many level failures - giving up\n");
165 goto done;
169 printf("check for correct aliases\n");
170 s1 = find("SIZE_INFO");
171 s2 = find("SIZE_INFORMATION");
172 if (s1 && s2) {
173 VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
174 VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
175 VAL_EQUAL(size_info, sectors_per_unit, size_info, sectors_per_unit);
176 VAL_EQUAL(size_info, bytes_per_sector, size_info, bytes_per_sector);
179 s1 = find("DEVICE_INFO");
180 s2 = find("DEVICE_INFORMATION");
181 if (s1 && s2) {
182 VAL_EQUAL(device_info, device_type, device_info, device_type);
183 VAL_EQUAL(device_info, characteristics, device_info, characteristics);
186 s1 = find("VOLUME_INFO");
187 s2 = find("VOLUME_INFORMATION");
188 if (s1 && s2) {
189 STRUCT_EQUAL(volume_info, create_time, volume_info, create_time);
190 VAL_EQUAL (volume_info, serial_number, volume_info, serial_number);
191 STR_EQUAL (volume_info, volume_name.s, volume_info, volume_name.s);
192 printf("volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
195 s1 = find("ATTRIBUTE_INFO");
196 s2 = find("ATTRIBUTE_INFORMATION");
197 if (s1 && s2) {
198 VAL_EQUAL(attribute_info, fs_attr,
199 attribute_info, fs_attr);
200 VAL_EQUAL(attribute_info, max_file_component_length,
201 attribute_info, max_file_component_length);
202 STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
203 printf("attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
206 printf("check for consistent disk sizes\n");
207 s1 = find("DSKATTR");
208 s2 = find("ALLOCATION");
209 if (s1 && s2) {
210 double size1, size2;
211 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
212 size1 = 1.0 *
213 s1->dskattr.out.units_total *
214 s1->dskattr.out.blocks_per_unit *
215 s1->dskattr.out.block_size / scale;
216 size2 = 1.0 *
217 s2->allocation.out.sectors_per_unit *
218 s2->allocation.out.total_alloc_units *
219 s2->allocation.out.bytes_per_sector / scale;
220 if (ABS(size1 - size2) > 1) {
221 printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
222 size1, size2);
223 ret = False;
225 printf("total disk = %.0f MB\n", size1*scale/1.0e6);
228 printf("check consistent free disk space\n");
229 s1 = find("DSKATTR");
230 s2 = find("ALLOCATION");
231 if (s1 && s2) {
232 double size1, size2;
233 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
234 size1 = 1.0 *
235 s1->dskattr.out.units_free *
236 s1->dskattr.out.blocks_per_unit *
237 s1->dskattr.out.block_size / scale;
238 size2 = 1.0 *
239 s2->allocation.out.sectors_per_unit *
240 s2->allocation.out.avail_alloc_units *
241 s2->allocation.out.bytes_per_sector / scale;
242 if (ABS(size1 - size2) > 1) {
243 printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
244 size1, size2);
245 ret = False;
247 printf("free disk = %.0f MB\n", size1*scale/1.0e6);
250 printf("volume info consistency\n");
251 s1 = find("VOLUME");
252 s2 = find("VOLUME_INFO");
253 if (s1 && s2) {
254 VAL_EQUAL(volume, serial_number, volume_info, serial_number);
255 STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
258 /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
259 available allocation units, not the total */
260 s1 = find("SIZE_INFO");
261 s2 = find("FULL_SIZE_INFORMATION");
262 if (s1 && s2) {
263 VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
264 VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
265 VAL_EQUAL(size_info, sectors_per_unit, full_size_information, sectors_per_unit);
266 VAL_EQUAL(size_info, bytes_per_sector, full_size_information, bytes_per_sector);
269 printf("check for non-zero unknown fields\n");
270 s1 = find("QUOTA_INFORMATION");
271 if (s1) {
272 VAL_UNKNOWN(quota_information, unknown[0]);
273 VAL_UNKNOWN(quota_information, unknown[1]);
274 VAL_UNKNOWN(quota_information, unknown[2]);
277 s1 = find("OBJECTID_INFORMATION");
278 if (s1) {
279 VAL_UNKNOWN(objectid_information, unknown[0]);
280 VAL_UNKNOWN(objectid_information, unknown[1]);
281 VAL_UNKNOWN(objectid_information, unknown[2]);
282 VAL_UNKNOWN(objectid_information, unknown[3]);
283 VAL_UNKNOWN(objectid_information, unknown[4]);
284 VAL_UNKNOWN(objectid_information, unknown[5]);
288 #define STR_CHECK(sname, stype, field, flags) do { \
289 s1 = find(sname); \
290 if (s1) { \
291 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli)) { \
292 printf("(%d) incorrect string termination in %s/%s\n", \
293 __LINE__, #stype, #field); \
294 ret = False; \
296 }} while (0)
298 printf("check for correct termination\n");
300 STR_CHECK("VOLUME", volume, volume_name, 0);
301 STR_CHECK("VOLUME_INFO", volume_info, volume_name, STR_UNICODE);
302 STR_CHECK("VOLUME_INFORMATION", volume_info, volume_name, STR_UNICODE);
303 STR_CHECK("ATTRIBUTE_INFO", attribute_info, fs_type, STR_UNICODE);
304 STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);
306 done:
307 torture_close_connection(cli);
308 talloc_free(mem_ctx);
309 return ret;