2 Unix SMB/CIFS implementation.
3 client file read/write routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) James Myers 2003
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
25 #define SETUP_REQUEST(cmd, wct, buflen) do { \
26 req = smbcli_request_setup(tree, cmd, wct, buflen); \
27 if (!req) return NULL; \
30 /****************************************************************************
31 low level read operation (async send)
32 ****************************************************************************/
33 _PUBLIC_
struct smbcli_request
*smb_raw_read_send(struct smbcli_tree
*tree
, union smb_read
*parms
)
35 bool bigoffset
= false;
36 struct smbcli_request
*req
= NULL
;
38 switch (parms
->generic
.level
) {
39 case RAW_READ_READBRAW
:
40 if (tree
->session
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
) {
43 SETUP_REQUEST(SMBreadbraw
, bigoffset
? 10:8, 0);
44 SSVAL(req
->out
.vwv
, VWV(0), parms
->readbraw
.in
.file
.fnum
);
45 SIVAL(req
->out
.vwv
, VWV(1), parms
->readbraw
.in
.offset
);
46 SSVAL(req
->out
.vwv
, VWV(3), parms
->readbraw
.in
.maxcnt
);
47 SSVAL(req
->out
.vwv
, VWV(4), parms
->readbraw
.in
.mincnt
);
48 SIVAL(req
->out
.vwv
, VWV(5), parms
->readbraw
.in
.timeout
);
49 SSVAL(req
->out
.vwv
, VWV(7), 0); /* reserved */
51 SIVAL(req
->out
.vwv
, VWV(8),parms
->readbraw
.in
.offset
>>32);
55 case RAW_READ_LOCKREAD
:
56 SETUP_REQUEST(SMBlockread
, 5, 0);
57 SSVAL(req
->out
.vwv
, VWV(0), parms
->lockread
.in
.file
.fnum
);
58 SSVAL(req
->out
.vwv
, VWV(1), parms
->lockread
.in
.count
);
59 SIVAL(req
->out
.vwv
, VWV(2), parms
->lockread
.in
.offset
);
60 SSVAL(req
->out
.vwv
, VWV(4), parms
->lockread
.in
.remaining
);
64 SETUP_REQUEST(SMBread
, 5, 0);
65 SSVAL(req
->out
.vwv
, VWV(0), parms
->read
.in
.file
.fnum
);
66 SSVAL(req
->out
.vwv
, VWV(1), parms
->read
.in
.count
);
67 SIVAL(req
->out
.vwv
, VWV(2), parms
->read
.in
.offset
);
68 SSVAL(req
->out
.vwv
, VWV(4), parms
->read
.in
.remaining
);
72 if (tree
->session
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
) {
75 SETUP_REQUEST(SMBreadX
, bigoffset
? 12 : 10, 0);
76 SSVAL(req
->out
.vwv
, VWV(0), SMB_CHAIN_NONE
);
77 SSVAL(req
->out
.vwv
, VWV(1), 0);
78 SSVAL(req
->out
.vwv
, VWV(2), parms
->readx
.in
.file
.fnum
);
79 SIVAL(req
->out
.vwv
, VWV(3), parms
->readx
.in
.offset
);
80 SSVAL(req
->out
.vwv
, VWV(5), parms
->readx
.in
.maxcnt
& 0xFFFF);
81 SSVAL(req
->out
.vwv
, VWV(6), parms
->readx
.in
.mincnt
);
82 SIVAL(req
->out
.vwv
, VWV(7), parms
->readx
.in
.maxcnt
>> 16);
83 SSVAL(req
->out
.vwv
, VWV(9), parms
->readx
.in
.remaining
);
85 * TODO: give an error when the offset is 64 bit
86 * and the server doesn't support it
89 SIVAL(req
->out
.vwv
, VWV(10),parms
->readx
.in
.offset
>>32);
91 if (parms
->readx
.in
.read_for_execute
) {
92 uint16_t flags2
= SVAL(req
->out
.hdr
, HDR_FLG2
);
93 flags2
|= FLAGS2_READ_PERMIT_EXECUTE
;
94 SSVAL(req
->out
.hdr
, HDR_FLG2
, flags2
);
102 if (!smbcli_request_send(req
)) {
103 smbcli_request_destroy(req
);
110 /****************************************************************************
111 low level read operation (async recv)
112 ****************************************************************************/
113 _PUBLIC_ NTSTATUS
smb_raw_read_recv(struct smbcli_request
*req
, union smb_read
*parms
)
115 if (!smbcli_request_receive(req
) ||
116 smbcli_request_is_error(req
)) {
120 switch (parms
->generic
.level
) {
121 case RAW_READ_READBRAW
:
122 parms
->readbraw
.out
.nread
= req
->in
.size
- NBT_HDR_SIZE
;
123 if (parms
->readbraw
.out
.nread
>
124 MAX(parms
->readx
.in
.mincnt
, parms
->readx
.in
.maxcnt
)) {
125 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
128 memcpy(parms
->readbraw
.out
.data
, req
->in
.buffer
+ NBT_HDR_SIZE
, parms
->readbraw
.out
.nread
);
131 case RAW_READ_LOCKREAD
:
132 SMBCLI_CHECK_WCT(req
, 5);
133 parms
->lockread
.out
.nread
= SVAL(req
->in
.vwv
, VWV(0));
134 if (parms
->lockread
.out
.nread
> parms
->lockread
.in
.count
||
135 !smbcli_raw_pull_data(&req
->in
.bufinfo
, req
->in
.data
+3,
136 parms
->lockread
.out
.nread
, parms
->lockread
.out
.data
)) {
137 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
142 /* there are 4 reserved words in the reply */
143 SMBCLI_CHECK_WCT(req
, 5);
144 parms
->read
.out
.nread
= SVAL(req
->in
.vwv
, VWV(0));
145 if (parms
->read
.out
.nread
> parms
->read
.in
.count
||
146 !smbcli_raw_pull_data(&req
->in
.bufinfo
, req
->in
.data
+3,
147 parms
->read
.out
.nread
, parms
->read
.out
.data
)) {
148 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
153 /* there are 5 reserved words in the reply */
154 SMBCLI_CHECK_WCT(req
, 12);
155 parms
->readx
.out
.remaining
= SVAL(req
->in
.vwv
, VWV(2));
156 parms
->readx
.out
.compaction_mode
= SVAL(req
->in
.vwv
, VWV(3));
157 parms
->readx
.out
.nread
= SVAL(req
->in
.vwv
, VWV(5));
158 parms
->readx
.out
.flags2
= req
->flags2
;
159 parms
->readx
.out
.data_offset
= SVAL(req
->in
.vwv
, VWV(6));
161 /* handle oversize replies for non-chained readx replies with
162 CAP_LARGE_READX. The snia spec has must to answer for. */
163 if ((req
->tree
->session
->transport
->negotiate
.capabilities
& CAP_LARGE_READX
)
164 && CVAL(req
->in
.vwv
, VWV(0)) == SMB_CHAIN_NONE
&&
165 req
->in
.size
>= 0x10000) {
166 parms
->readx
.out
.nread
+= (SVAL(req
->in
.vwv
, VWV(7)) << 16);
167 if (req
->in
.hdr
+ SVAL(req
->in
.vwv
, VWV(6)) +
168 parms
->readx
.out
.nread
<=
169 req
->in
.buffer
+ req
->in
.size
) {
170 req
->in
.data_size
+= (SVAL(req
->in
.vwv
, VWV(7)) << 16);
172 /* update the bufinfo with the new size */
173 smb_setup_bufinfo(req
);
177 if (parms
->readx
.out
.nread
> MAX(parms
->readx
.in
.mincnt
, parms
->readx
.in
.maxcnt
) ||
178 !smbcli_raw_pull_data(&req
->in
.bufinfo
, req
->in
.hdr
+ SVAL(req
->in
.vwv
, VWV(6)),
179 parms
->readx
.out
.nread
,
180 parms
->readx
.out
.data
)) {
181 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
186 req
->status
= NT_STATUS_INTERNAL_ERROR
;
191 return smbcli_request_destroy(req
);
194 /****************************************************************************
195 low level read operation (sync interface)
196 ****************************************************************************/
197 _PUBLIC_ NTSTATUS
smb_raw_read(struct smbcli_tree
*tree
, union smb_read
*parms
)
199 struct smbcli_request
*req
= smb_raw_read_send(tree
, parms
);
200 return smb_raw_read_recv(req
, parms
);
204 /****************************************************************************
205 raw write interface (async send)
206 ****************************************************************************/
207 _PUBLIC_
struct smbcli_request
*smb_raw_write_send(struct smbcli_tree
*tree
, union smb_write
*parms
)
209 bool bigoffset
= false;
210 struct smbcli_request
*req
= NULL
;
212 switch (parms
->generic
.level
) {
213 case RAW_WRITE_WRITEUNLOCK
:
214 SETUP_REQUEST(SMBwriteunlock
, 5, 3 + parms
->writeunlock
.in
.count
);
215 SSVAL(req
->out
.vwv
, VWV(0), parms
->writeunlock
.in
.file
.fnum
);
216 SSVAL(req
->out
.vwv
, VWV(1), parms
->writeunlock
.in
.count
);
217 SIVAL(req
->out
.vwv
, VWV(2), parms
->writeunlock
.in
.offset
);
218 SSVAL(req
->out
.vwv
, VWV(4), parms
->writeunlock
.in
.remaining
);
219 SCVAL(req
->out
.data
, 0, SMB_DATA_BLOCK
);
220 SSVAL(req
->out
.data
, 1, parms
->writeunlock
.in
.count
);
221 if (parms
->writeunlock
.in
.count
> 0) {
222 memcpy(req
->out
.data
+3, parms
->writeunlock
.in
.data
,
223 parms
->writeunlock
.in
.count
);
227 case RAW_WRITE_WRITE
:
228 SETUP_REQUEST(SMBwrite
, 5, 3 + parms
->write
.in
.count
);
229 SSVAL(req
->out
.vwv
, VWV(0), parms
->write
.in
.file
.fnum
);
230 SSVAL(req
->out
.vwv
, VWV(1), parms
->write
.in
.count
);
231 SIVAL(req
->out
.vwv
, VWV(2), parms
->write
.in
.offset
);
232 SSVAL(req
->out
.vwv
, VWV(4), parms
->write
.in
.remaining
);
233 SCVAL(req
->out
.data
, 0, SMB_DATA_BLOCK
);
234 SSVAL(req
->out
.data
, 1, parms
->write
.in
.count
);
235 if (parms
->write
.in
.count
> 0) {
236 memcpy(req
->out
.data
+3, parms
->write
.in
.data
, parms
->write
.in
.count
);
240 case RAW_WRITE_WRITECLOSE
:
241 SETUP_REQUEST(SMBwriteclose
, 6, 1 + parms
->writeclose
.in
.count
);
242 SSVAL(req
->out
.vwv
, VWV(0), parms
->writeclose
.in
.file
.fnum
);
243 SSVAL(req
->out
.vwv
, VWV(1), parms
->writeclose
.in
.count
);
244 SIVAL(req
->out
.vwv
, VWV(2), parms
->writeclose
.in
.offset
);
245 raw_push_dos_date3(tree
->session
->transport
,
246 req
->out
.vwv
, VWV(4), parms
->writeclose
.in
.mtime
);
247 SCVAL(req
->out
.data
, 0, 0);
248 if (parms
->writeclose
.in
.count
> 0) {
249 memcpy(req
->out
.data
+1, parms
->writeclose
.in
.data
,
250 parms
->writeclose
.in
.count
);
254 case RAW_WRITE_WRITEX
:
255 if (tree
->session
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
) {
258 SETUP_REQUEST(SMBwriteX
, bigoffset
? 14 : 12, parms
->writex
.in
.count
);
259 SSVAL(req
->out
.vwv
, VWV(0), SMB_CHAIN_NONE
);
260 SSVAL(req
->out
.vwv
, VWV(1), 0);
261 SSVAL(req
->out
.vwv
, VWV(2), parms
->writex
.in
.file
.fnum
);
262 SIVAL(req
->out
.vwv
, VWV(3), parms
->writex
.in
.offset
);
263 SIVAL(req
->out
.vwv
, VWV(5), 0); /* reserved */
264 SSVAL(req
->out
.vwv
, VWV(7), parms
->writex
.in
.wmode
);
265 SSVAL(req
->out
.vwv
, VWV(8), parms
->writex
.in
.remaining
);
266 SSVAL(req
->out
.vwv
, VWV(9), parms
->writex
.in
.count
>>16);
267 SSVAL(req
->out
.vwv
, VWV(10), parms
->writex
.in
.count
);
268 SSVAL(req
->out
.vwv
, VWV(11), PTR_DIFF(req
->out
.data
, req
->out
.hdr
));
270 SIVAL(req
->out
.vwv
,VWV(12),parms
->writex
.in
.offset
>>32);
272 if (parms
->writex
.in
.count
> 0) {
273 memcpy(req
->out
.data
, parms
->writex
.in
.data
, parms
->writex
.in
.count
);
277 case RAW_WRITE_SPLWRITE
:
278 SETUP_REQUEST(SMBsplwr
, 1, parms
->splwrite
.in
.count
);
279 SSVAL(req
->out
.vwv
, VWV(0), parms
->splwrite
.in
.file
.fnum
);
280 if (parms
->splwrite
.in
.count
> 0) {
281 memcpy(req
->out
.data
, parms
->splwrite
.in
.data
, parms
->splwrite
.in
.count
);
289 if (!smbcli_request_send(req
)) {
290 smbcli_request_destroy(req
);
298 /****************************************************************************
299 raw write interface (async recv)
300 ****************************************************************************/
301 _PUBLIC_ NTSTATUS
smb_raw_write_recv(struct smbcli_request
*req
, union smb_write
*parms
)
303 if (!smbcli_request_receive(req
) ||
304 !NT_STATUS_IS_OK(req
->status
)) {
308 switch (parms
->generic
.level
) {
309 case RAW_WRITE_WRITEUNLOCK
:
310 SMBCLI_CHECK_WCT(req
, 1);
311 parms
->writeunlock
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(0));
313 case RAW_WRITE_WRITE
:
314 SMBCLI_CHECK_WCT(req
, 1);
315 parms
->write
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(0));
317 case RAW_WRITE_WRITECLOSE
:
318 SMBCLI_CHECK_WCT(req
, 1);
319 parms
->writeclose
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(0));
321 case RAW_WRITE_WRITEX
:
322 SMBCLI_CHECK_WCT(req
, 6);
323 parms
->writex
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(2));
324 parms
->writex
.out
.nwritten
+= (CVAL(req
->in
.vwv
, VWV(4)) << 16);
325 parms
->writex
.out
.remaining
= SVAL(req
->in
.vwv
, VWV(3));
327 case RAW_WRITE_SPLWRITE
:
330 req
->status
= NT_STATUS_INTERNAL_ERROR
;
335 return smbcli_request_destroy(req
);
338 /****************************************************************************
339 raw write interface (sync interface)
340 ****************************************************************************/
341 _PUBLIC_ NTSTATUS
smb_raw_write(struct smbcli_tree
*tree
, union smb_write
*parms
)
343 struct smbcli_request
*req
= smb_raw_write_send(tree
, parms
);
344 return smb_raw_write_recv(req
, parms
);