first public release of samba4 code
[kai/samba.git] / source4 / libcli / raw / rawfsinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    RAW_QFS_* operations
5
6    Copyright (C) Andrew Tridgell 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /****************************************************************************
26  Query FS Info - SMBdskattr call (async send)
27 ****************************************************************************/
28 static struct cli_request *smb_raw_dskattr_send(struct cli_tree *tree, 
29                                                 union smb_fsinfo *fsinfo)
30 {
31         struct cli_request *req; 
32
33         req = cli_request_setup(tree, SMBdskattr, 0, 0);
34
35         if (!cli_request_send(req)) {
36                 cli_request_destroy(req);
37                 return NULL;
38         }
39
40         return req;
41 }
42
43 /****************************************************************************
44  Query FS Info - SMBdskattr call (async recv)
45 ****************************************************************************/
46 static NTSTATUS smb_raw_dskattr_recv(struct cli_request *req,
47                                      union smb_fsinfo *fsinfo)
48 {
49         if (!cli_request_receive(req) ||
50             cli_request_is_error(req)) {
51                 goto failed;
52         }
53
54         CLI_CHECK_WCT(req, 5);
55         fsinfo->dskattr.out.units_total =     SVAL(req->in.vwv, VWV(0));
56         fsinfo->dskattr.out.blocks_per_unit = SVAL(req->in.vwv, VWV(1));
57         fsinfo->dskattr.out.block_size =      SVAL(req->in.vwv, VWV(2));
58         fsinfo->dskattr.out.units_free =      SVAL(req->in.vwv, VWV(3));
59
60 failed:
61         return cli_request_destroy(req);
62 }
63
64
65 /****************************************************************************
66  RAW_QFS_ trans2 interface via blobs (async send)
67 ****************************************************************************/
68 static struct cli_request *smb_raw_qfsinfo_send(struct cli_tree *tree,
69                                                 TALLOC_CTX *mem_ctx,
70                                                 uint16 info_level)
71 {
72         struct smb_trans2 tp;
73         uint16 setup = TRANSACT2_QFSINFO;
74         
75         tp.in.max_setup = 0;
76         tp.in.flags = 0; 
77         tp.in.timeout = 0;
78         tp.in.setup_count = 1;
79         tp.in.max_param = 0;
80         tp.in.max_data = 0x1000; /* plenty for all possible QFS levels */
81         tp.in.setup = &setup;
82         tp.in.data = data_blob(NULL, 0);
83         tp.in.timeout = 0;
84
85         tp.in.params = data_blob_talloc(mem_ctx, NULL, 2);
86         if (!tp.in.params.data) {
87                 return NULL;
88         }
89         SSVAL(tp.in.params.data, 0, info_level);
90
91         return smb_raw_trans2_send(tree, &tp);
92 }
93
94 /****************************************************************************
95  RAW_QFS_ trans2 interface via blobs (async recv)
96 ****************************************************************************/
97 static NTSTATUS smb_raw_qfsinfo_blob_recv(struct cli_request *req,
98                                           TALLOC_CTX *mem_ctx,
99                                           DATA_BLOB *blob)
100 {
101         struct smb_trans2 tp;
102         NTSTATUS status;
103         
104         status = smb_raw_trans2_recv(req, mem_ctx, &tp);
105         
106         if (NT_STATUS_IS_OK(status)) {
107                 (*blob) = tp.out.data;
108         }
109
110         return status;
111 }
112
113
114 /* local macros to make the code more readable */
115 #define QFS_CHECK_MIN_SIZE(size) if (blob.length < (size)) { \
116       DEBUG(1,("Unexpected QFS reply size %d for level %u - expected min of %d\n", \
117                blob.length, fsinfo->generic.level, (size))); \
118       status = NT_STATUS_INFO_LENGTH_MISMATCH; \
119       goto failed; \
120 }
121 #define QFS_CHECK_SIZE(size) if (blob.length != (size)) { \
122       DEBUG(1,("Unexpected QFS reply size %d for level %u - expected %d\n", \
123                blob.length, fsinfo->generic.level, (size))); \
124       status = NT_STATUS_INFO_LENGTH_MISMATCH; \
125       goto failed; \
126 }
127
128
129 /****************************************************************************
130  Query FSInfo raw interface (async send)
131 ****************************************************************************/
132 struct cli_request *smb_raw_fsinfo_send(struct cli_tree *tree, 
133                                         TALLOC_CTX *mem_ctx, 
134                                         union smb_fsinfo *fsinfo)
135 {
136         uint16 info_level;
137
138         /* handle the only non-trans2 call separately */
139         if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
140                 return smb_raw_dskattr_send(tree, fsinfo);
141         }
142         if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
143                 return NULL;
144         }
145
146         /* the headers map the trans2 levels direct to info levels */
147         info_level = (uint16)fsinfo->generic.level;
148
149         return smb_raw_qfsinfo_send(tree, mem_ctx, info_level);
150 }
151
152
153 /****************************************************************************
154  Query FSInfo raw interface (async recv)
155 ****************************************************************************/
156 NTSTATUS smb_raw_fsinfo_recv(struct cli_request *req, 
157                              TALLOC_CTX *mem_ctx, 
158                              union smb_fsinfo *fsinfo)
159 {
160         DATA_BLOB blob;
161         NTSTATUS status;
162         int i;
163         struct cli_session *session = req?req->session:NULL;
164
165         if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
166                 return smb_raw_dskattr_recv(req, fsinfo);
167         }
168
169         status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob);
170         if (!NT_STATUS_IS_OK(status)) {
171                 return status;
172         }
173
174         /* parse the results */
175         switch (fsinfo->generic.level) {
176         case RAW_QFS_GENERIC:
177         case RAW_QFS_DSKATTR:
178                 /* handled above */
179                 break;
180
181         case RAW_QFS_ALLOCATION:
182                 QFS_CHECK_SIZE(18);
183                 fsinfo->allocation.out.fs_id =             IVAL(blob.data,  0);
184                 fsinfo->allocation.out.sectors_per_unit =  IVAL(blob.data,  4);
185                 fsinfo->allocation.out.total_alloc_units = IVAL(blob.data,  8);
186                 fsinfo->allocation.out.avail_alloc_units = IVAL(blob.data, 12);
187                 fsinfo->allocation.out.bytes_per_sector =  SVAL(blob.data, 16); 
188                 break;          
189
190         case RAW_QFS_VOLUME:
191                 QFS_CHECK_MIN_SIZE(5);
192                 fsinfo->volume.out.serial_number = IVAL(blob.data, 0);
193                 cli_blob_pull_string(session, mem_ctx, &blob, 
194                                      &fsinfo->volume.out.volume_name,
195                                      4, 5, STR_LEN8BIT | STR_NOALIGN);
196                 break;          
197
198         case RAW_QFS_VOLUME_INFO:
199         case RAW_QFS_VOLUME_INFORMATION:
200                 QFS_CHECK_MIN_SIZE(18);
201                 fsinfo->volume_info.out.create_time   = cli_pull_nttime(blob.data, 0);
202                 fsinfo->volume_info.out.serial_number = IVAL(blob.data, 8);
203                 cli_blob_pull_string(session, mem_ctx, &blob, 
204                                      &fsinfo->volume_info.out.volume_name,
205                                      12, 18, STR_UNICODE);
206                 break;          
207
208         case RAW_QFS_SIZE_INFO:
209         case RAW_QFS_SIZE_INFORMATION:
210                 QFS_CHECK_SIZE(24);
211                 fsinfo->size_info.out.total_alloc_units = BVAL(blob.data,  0);
212                 fsinfo->size_info.out.avail_alloc_units = BVAL(blob.data,  8);
213                 fsinfo->size_info.out.sectors_per_unit =  IVAL(blob.data, 16);
214                 fsinfo->size_info.out.bytes_per_sector =  IVAL(blob.data, 20); 
215                 break;          
216
217         case RAW_QFS_DEVICE_INFO:
218         case RAW_QFS_DEVICE_INFORMATION:
219                 QFS_CHECK_SIZE(8);
220                 fsinfo->device_info.out.device_type     = IVAL(blob.data,  0);
221                 fsinfo->device_info.out.characteristics = IVAL(blob.data,  4);
222                 break;          
223
224         case RAW_QFS_ATTRIBUTE_INFO:
225         case RAW_QFS_ATTRIBUTE_INFORMATION:
226                 QFS_CHECK_MIN_SIZE(12);
227                 fsinfo->attribute_info.out.fs_attr   =                 IVAL(blob.data, 0);
228                 fsinfo->attribute_info.out.max_file_component_length = IVAL(blob.data, 4);
229                 cli_blob_pull_string(session, mem_ctx, &blob, 
230                                      &fsinfo->attribute_info.out.fs_type,
231                                      8, 12, STR_UNICODE);
232                 break;          
233
234         case RAW_QFS_UNIX_INFO:
235                 QFS_CHECK_SIZE(12);
236                 fsinfo->unix_info.out.major_version = SVAL(blob.data, 0);
237                 fsinfo->unix_info.out.minor_version = SVAL(blob.data, 2);
238                 fsinfo->unix_info.out.capability    = SVAL(blob.data, 4);
239                 break;
240
241         case RAW_QFS_QUOTA_INFORMATION:
242                 QFS_CHECK_SIZE(48);
243                 fsinfo->quota_information.out.unknown[0] =  BVAL(blob.data,  0);
244                 fsinfo->quota_information.out.unknown[1] =  BVAL(blob.data,  8);
245                 fsinfo->quota_information.out.unknown[2] =  BVAL(blob.data, 16);
246                 fsinfo->quota_information.out.quota_soft =  BVAL(blob.data, 24);
247                 fsinfo->quota_information.out.quota_hard =  BVAL(blob.data, 32);
248                 fsinfo->quota_information.out.quota_flags = BVAL(blob.data, 40);
249                 break;          
250
251         case RAW_QFS_FULL_SIZE_INFORMATION:
252                 QFS_CHECK_SIZE(32);
253                 fsinfo->full_size_information.out.total_alloc_units =        BVAL(blob.data,  0);
254                 fsinfo->full_size_information.out.call_avail_alloc_units =   BVAL(blob.data,  8);
255                 fsinfo->full_size_information.out.actual_avail_alloc_units = BVAL(blob.data, 16);
256                 fsinfo->full_size_information.out.sectors_per_unit =         IVAL(blob.data, 24);
257                 fsinfo->full_size_information.out.bytes_per_sector =         IVAL(blob.data, 28);
258                 break;          
259
260         case RAW_QFS_OBJECTID_INFORMATION:
261                 QFS_CHECK_SIZE(64);
262                 memcpy(fsinfo->objectid_information.out.guid.info, blob.data, GUID_SIZE);
263                 for (i=0;i<6;i++) {
264                         fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8);
265                 }
266                 break;          
267         }
268
269 failed:
270         return status;
271 }
272
273 /****************************************************************************
274  Query FSInfo raw interface (sync interface)
275 ****************************************************************************/
276 NTSTATUS smb_raw_fsinfo(struct cli_tree *tree, 
277                         TALLOC_CTX *mem_ctx, 
278                         union smb_fsinfo *fsinfo)
279 {
280         struct cli_request *req = smb_raw_fsinfo_send(tree, mem_ctx, fsinfo);
281         return smb_raw_fsinfo_recv(req, mem_ctx, fsinfo);
282 }