s3: Fix bug #9085.
[Samba.git] / source4 / torture / raw / qfsinfo.c
blobc1c77edba99ddb9a9409d959668352e3a10050b1
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 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/>.
20 #include "includes.h"
21 #include "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/libcli.h"
24 #include "torture/util.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(struct torture_context *torture,
124 struct smbcli_state *cli)
126 int i;
127 bool ret = true;
128 int count;
129 union smb_fsinfo *s1, *s2;
131 /* scan all the levels, pulling the results */
132 for (i=0; levels[i].name; i++) {
133 torture_comment(torture, "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) {
143 continue;
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));
149 count++;
153 if (count != 0) {
154 torture_comment(torture, "%d levels failed\n", count);
155 torture_assert(torture, count > 13, "too many level failures - giving up");
158 torture_comment(torture, "check for correct aliases\n");
159 s1 = find("SIZE_INFO");
160 s2 = find("SIZE_INFORMATION");
161 if (s1 && s2) {
162 VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
163 VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
164 VAL_EQUAL(size_info, sectors_per_unit, size_info, sectors_per_unit);
165 VAL_EQUAL(size_info, bytes_per_sector, size_info, bytes_per_sector);
168 s1 = find("DEVICE_INFO");
169 s2 = find("DEVICE_INFORMATION");
170 if (s1 && s2) {
171 VAL_EQUAL(device_info, device_type, device_info, device_type);
172 VAL_EQUAL(device_info, characteristics, device_info, characteristics);
175 s1 = find("VOLUME_INFO");
176 s2 = find("VOLUME_INFORMATION");
177 if (s1 && s2) {
178 STRUCT_EQUAL(volume_info, create_time, volume_info, create_time);
179 VAL_EQUAL (volume_info, serial_number, volume_info, serial_number);
180 STR_EQUAL (volume_info, volume_name.s, volume_info, volume_name.s);
181 torture_comment(torture, "volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
184 s1 = find("ATTRIBUTE_INFO");
185 s2 = find("ATTRIBUTE_INFORMATION");
186 if (s1 && s2) {
187 VAL_EQUAL(attribute_info, fs_attr,
188 attribute_info, fs_attr);
189 VAL_EQUAL(attribute_info, max_file_component_length,
190 attribute_info, max_file_component_length);
191 STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
192 torture_comment(torture, "attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
195 torture_comment(torture, "check for consistent disk sizes\n");
196 s1 = find("DSKATTR");
197 s2 = find("ALLOCATION");
198 if (s1 && s2) {
199 double size1, size2;
200 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
201 size1 = 1.0 *
202 s1->dskattr.out.units_total *
203 s1->dskattr.out.blocks_per_unit *
204 s1->dskattr.out.block_size / scale;
205 size2 = 1.0 *
206 s2->allocation.out.sectors_per_unit *
207 s2->allocation.out.total_alloc_units *
208 s2->allocation.out.bytes_per_sector / scale;
209 if (abs(size1 - size2) > 1) {
210 printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
211 size1, size2);
212 ret = false;
214 torture_comment(torture, "total disk = %.0f MB\n", size1*scale/1.0e6);
217 torture_comment(torture, "check consistent free disk space\n");
218 s1 = find("DSKATTR");
219 s2 = find("ALLOCATION");
220 if (s1 && s2) {
221 double size1, size2;
222 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
223 size1 = 1.0 *
224 s1->dskattr.out.units_free *
225 s1->dskattr.out.blocks_per_unit *
226 s1->dskattr.out.block_size / scale;
227 size2 = 1.0 *
228 s2->allocation.out.sectors_per_unit *
229 s2->allocation.out.avail_alloc_units *
230 s2->allocation.out.bytes_per_sector / scale;
231 if (abs(size1 - size2) > 1) {
232 printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
233 size1, size2);
234 ret = false;
236 torture_comment(torture, "free disk = %.0f MB\n", size1*scale/1.0e6);
239 torture_comment(torture, "volume info consistency\n");
240 s1 = find("VOLUME");
241 s2 = find("VOLUME_INFO");
242 if (s1 && s2) {
243 VAL_EQUAL(volume, serial_number, volume_info, serial_number);
244 STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
247 /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
248 available allocation units, not the total */
249 s1 = find("SIZE_INFO");
250 s2 = find("FULL_SIZE_INFORMATION");
251 if (s1 && s2) {
252 VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
253 VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
254 VAL_EQUAL(size_info, sectors_per_unit, full_size_information, sectors_per_unit);
255 VAL_EQUAL(size_info, bytes_per_sector, full_size_information, bytes_per_sector);
258 printf("check for non-zero unknown fields\n");
259 s1 = find("QUOTA_INFORMATION");
260 if (s1) {
261 VAL_UNKNOWN(quota_information, unknown[0]);
262 VAL_UNKNOWN(quota_information, unknown[1]);
263 VAL_UNKNOWN(quota_information, unknown[2]);
266 s1 = find("OBJECTID_INFORMATION");
267 if (s1) {
268 VAL_UNKNOWN(objectid_information, unknown[0]);
269 VAL_UNKNOWN(objectid_information, unknown[1]);
270 VAL_UNKNOWN(objectid_information, unknown[2]);
271 VAL_UNKNOWN(objectid_information, unknown[3]);
272 VAL_UNKNOWN(objectid_information, unknown[4]);
273 VAL_UNKNOWN(objectid_information, unknown[5]);
277 #define STR_CHECK(sname, stype, field, flags) do { \
278 s1 = find(sname); \
279 if (s1) { \
280 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
281 printf("(%d) incorrect string termination in %s/%s\n", \
282 __LINE__, #stype, #field); \
283 ret = false; \
285 }} while (0)
287 torture_comment(torture, "check for correct termination\n");
289 STR_CHECK("VOLUME", volume, volume_name, 0);
290 STR_CHECK("VOLUME_INFO", volume_info, volume_name, STR_UNICODE);
291 STR_CHECK("VOLUME_INFORMATION", volume_info, volume_name, STR_UNICODE);
292 STR_CHECK("ATTRIBUTE_INFO", attribute_info, fs_type, STR_UNICODE);
293 STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);
295 return ret;