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