d302435a6c6f2030ddf7514d6fb663e5be9dc792
[abartlet/samba.git/.git] / source4 / torture / raw / qfsinfo.c
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23
24
25 static 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         {"OBJECTID_INFORMATION",  RAW_QFS_OBJECTID_INFORMATION, },
47         { NULL, }
48 };
49
50
51 /*
52   find a level in the levels[] table
53 */
54 static union smb_fsinfo *find(const char *name)
55 {
56         int i;
57         for (i=0; levels[i].name; i++) {
58                 if (strcmp(name, levels[i].name) == 0 &&
59                     NT_STATUS_IS_OK(levels[i].status)) {
60                         return &levels[i].fsinfo;
61                 }
62         }
63         return NULL;
64 }
65
66 /* local macros to make the code below more readable */
67 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
68         printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
69                #n1, #v1, (uint_t)s1->n1.out.v1, \
70                #n2, #v2, (uint_t)s2->n2.out.v2, \
71                __FILE__, __LINE__); \
72         ret = False; \
73 }} while(0)
74
75 #define STR_EQUAL(n1, v1, n2, v2) do {if (!s1->n1.out.v1 && !s2->n2.out.v2) return True; \
76        if (!s1->n1.out.v1 || !s2->n2.out.v2) return False; \
77        if (strcmp(s1->n1.out.v1, s2->n2.out.v2)) { \
78          printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
79                #n1, #v1, s1->n1.out.v1, \
80                #n2, #v2, s2->n2.out.v2, \
81                __FILE__, __LINE__); \
82         ret = False; \
83 }} while(0)
84
85 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
86         printf("%s/%s != %s/%s at %s(%d)\n", \
87                #n1, #v1, \
88                #n2, #v2, \
89                __FILE__, __LINE__); \
90         ret = False; \
91 }} while(0)
92
93 /* used to find hints on unknown values - and to make sure 
94    we zero-fill */
95 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
96         printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
97                #n1, #v1, \
98                (uint_t)s1->n1.out.v1, \
99                (uint_t)s1->n1.out.v1, \
100                __FILE__, __LINE__); \
101         ret = False; \
102 }} while(0)
103
104 /* basic testing of all RAW_QFS_* calls 
105    for each call we test that it succeeds, and where possible test 
106    for consistency between the calls. 
107
108    Some of the consistency tests assume that the target filesystem is
109    quiescent, which is sometimes hard to achieve
110 */
111 BOOL torture_raw_qfsinfo(void)
112 {
113         struct smbcli_state *cli;
114         int i;
115         BOOL ret = True;
116         int count;
117         union smb_fsinfo *s1, *s2;      
118         TALLOC_CTX *mem_ctx;
119
120         if (!torture_open_connection(&cli)) {
121                 return False;
122         }
123
124         mem_ctx = talloc_init("torture_qfsinfo");
125         
126         /* scan all the levels, pulling the results */
127         for (i=0; levels[i].name; i++) {
128                 printf("Running level %s\n", levels[i].name);
129                 levels[i].fsinfo.generic.level = levels[i].level;
130                 levels[i].status = smb_raw_fsinfo(cli->tree, mem_ctx, &levels[i].fsinfo);
131         }
132
133         /* check for completely broken levels */
134         for (count=i=0; levels[i].name; i++) {
135                 uint32_t cap = cli->transport->negotiate.capabilities;
136                 /* see if this server claims to support this level */
137                 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
138                         continue;
139                 }
140                 
141                 if (!NT_STATUS_IS_OK(levels[i].status)) {
142                         printf("ERROR: level %s failed - %s\n", 
143                                levels[i].name, nt_errstr(levels[i].status));
144                         count++;
145                 }
146         }
147
148         if (count != 0) {
149                 ret = False;
150                 printf("%d levels failed\n", count);
151                 if (count > 13) {
152                         printf("too many level failures - giving up\n");
153                         goto done;
154                 }
155         }
156
157         printf("check for correct aliases\n");
158         s1 = find("SIZE_INFO");
159         s2 = find("SIZE_INFORMATION");
160         if (s1 && s2) {
161                 VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
162                 VAL_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
163                 VAL_EQUAL(size_info, sectors_per_unit,  size_info, sectors_per_unit);
164                 VAL_EQUAL(size_info, bytes_per_sector,  size_info, bytes_per_sector);
165         }       
166
167         s1 = find("DEVICE_INFO");
168         s2 = find("DEVICE_INFORMATION");
169         if (s1 && s2) {
170                 VAL_EQUAL(device_info, device_type,     device_info, device_type);
171                 VAL_EQUAL(device_info, characteristics, device_info, characteristics);
172         }       
173
174         s1 = find("VOLUME_INFO");
175         s2 = find("VOLUME_INFORMATION");
176         if (s1 && s2) {
177                 STRUCT_EQUAL(volume_info, create_time,    volume_info, create_time);
178                 VAL_EQUAL   (volume_info, serial_number,  volume_info, serial_number);
179                 STR_EQUAL   (volume_info, volume_name.s,    volume_info, volume_name.s);
180                 printf("volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
181         }       
182
183         s1 = find("ATTRIBUTE_INFO");
184         s2 = find("ATTRIBUTE_INFORMATION");
185         if (s1 && s2) {
186                 VAL_EQUAL(attribute_info, fs_attr,    
187                           attribute_info, fs_attr);
188                 VAL_EQUAL(attribute_info, max_file_component_length, 
189                           attribute_info, max_file_component_length);
190                 STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
191                 printf("attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
192         }       
193
194         printf("check for consistent disk sizes\n");
195         s1 = find("DSKATTR");
196         s2 = find("ALLOCATION");
197         if (s1 && s2) {
198                 double size1, size2;
199                 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
200                 size1 = 1.0 * 
201                         s1->dskattr.out.units_total * 
202                         s1->dskattr.out.blocks_per_unit * 
203                         s1->dskattr.out.block_size / scale;
204                 size2 = 1.0 *
205                         s2->allocation.out.sectors_per_unit *
206                         s2->allocation.out.total_alloc_units *
207                         s2->allocation.out.bytes_per_sector / scale;
208                 if (ABS(size1 - size2) > 1) {
209                         printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n", 
210                                size1, size2);
211                         ret = False;
212                 }
213                 printf("total disk = %.0f MB\n", size1*scale/1.0e6);
214         }
215
216         printf("check consistent free disk space\n");
217         s1 = find("DSKATTR");
218         s2 = find("ALLOCATION");
219         if (s1 && s2) {
220                 double size1, size2;
221                 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
222                 size1 = 1.0 * 
223                         s1->dskattr.out.units_free * 
224                         s1->dskattr.out.blocks_per_unit * 
225                         s1->dskattr.out.block_size / scale;
226                 size2 = 1.0 *
227                         s2->allocation.out.sectors_per_unit *
228                         s2->allocation.out.avail_alloc_units *
229                         s2->allocation.out.bytes_per_sector / scale;
230                 if (ABS(size1 - size2) > 1) {
231                         printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n", 
232                                size1, size2);
233                         ret = False;
234                 }
235                 printf("free disk = %.0f MB\n", size1*scale/1.0e6);
236         }
237         
238         printf("volume info consistency\n");
239         s1 = find("VOLUME");
240         s2 = find("VOLUME_INFO");
241         if (s1 && s2) {
242                 VAL_EQUAL(volume, serial_number,  volume_info, serial_number);
243                 STR_EQUAL(volume, volume_name.s,  volume_info, volume_name.s);
244         }       
245
246         /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
247            available allocation units, not the total */
248         s1 = find("SIZE_INFO");
249         s2 = find("FULL_SIZE_INFORMATION");
250         if (s1 && s2) {
251                 VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
252                 VAL_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
253                 VAL_EQUAL(size_info, sectors_per_unit,  full_size_information, sectors_per_unit);
254                 VAL_EQUAL(size_info, bytes_per_sector,  full_size_information, bytes_per_sector);
255         }       
256
257         printf("check for non-zero unknown fields\n");
258         s1 = find("QUOTA_INFORMATION");
259         if (s1) {
260                 VAL_UNKNOWN(quota_information, unknown[0]);
261                 VAL_UNKNOWN(quota_information, unknown[1]);
262                 VAL_UNKNOWN(quota_information, unknown[2]);
263         }
264
265         s1 = find("OBJECTID_INFORMATION");
266         if (s1) {
267                 VAL_UNKNOWN(objectid_information, unknown[0]);
268                 VAL_UNKNOWN(objectid_information, unknown[1]);
269                 VAL_UNKNOWN(objectid_information, unknown[2]);
270                 VAL_UNKNOWN(objectid_information, unknown[3]);
271                 VAL_UNKNOWN(objectid_information, unknown[4]);
272                 VAL_UNKNOWN(objectid_information, unknown[5]);
273         }
274
275
276 #define STR_CHECK(sname, stype, field, flags) do { \
277         s1 = find(sname); \
278         if (s1) { \
279                 if (wire_bad_flags(&s1->stype.out.field, flags, cli)) { \
280                         printf("(%d) incorrect string termination in %s/%s\n", \
281                                __LINE__, #stype, #field); \
282                         ret = False; \
283                 } \
284         }} while (0)
285
286         printf("check for correct termination\n");
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 done:
294         torture_close_connection(cli);
295         talloc_destroy(mem_ctx);
296         return ret;
297 }