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));
159 /* handle oversize replies for non-chained readx replies with
160 CAP_LARGE_READX. The snia spec has must to answer for. */
161 if ((req
->tree
->session
->transport
->negotiate
.capabilities
& CAP_LARGE_READX
)
162 && CVAL(req
->in
.vwv
, VWV(0)) == SMB_CHAIN_NONE
&&
163 req
->in
.size
>= 0x10000) {
164 parms
->readx
.out
.nread
+= (SVAL(req
->in
.vwv
, VWV(7)) << 16);
165 if (req
->in
.hdr
+ SVAL(req
->in
.vwv
, VWV(6)) +
166 parms
->readx
.out
.nread
<=
167 req
->in
.buffer
+ req
->in
.size
) {
168 req
->in
.data_size
+= (SVAL(req
->in
.vwv
, VWV(7)) << 16);
170 /* update the bufinfo with the new size */
171 smb_setup_bufinfo(req
);
175 if (parms
->readx
.out
.nread
> MAX(parms
->readx
.in
.mincnt
, parms
->readx
.in
.maxcnt
) ||
176 !smbcli_raw_pull_data(&req
->in
.bufinfo
, req
->in
.hdr
+ SVAL(req
->in
.vwv
, VWV(6)),
177 parms
->readx
.out
.nread
,
178 parms
->readx
.out
.data
)) {
179 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
184 req
->status
= NT_STATUS_INTERNAL_ERROR
;
189 return smbcli_request_destroy(req
);
192 /****************************************************************************
193 low level read operation (sync interface)
194 ****************************************************************************/
195 _PUBLIC_ NTSTATUS
smb_raw_read(struct smbcli_tree
*tree
, union smb_read
*parms
)
197 struct smbcli_request
*req
= smb_raw_read_send(tree
, parms
);
198 return smb_raw_read_recv(req
, parms
);
202 /****************************************************************************
203 raw write interface (async send)
204 ****************************************************************************/
205 _PUBLIC_
struct smbcli_request
*smb_raw_write_send(struct smbcli_tree
*tree
, union smb_write
*parms
)
207 bool bigoffset
= false;
208 struct smbcli_request
*req
= NULL
;
210 switch (parms
->generic
.level
) {
211 case RAW_WRITE_WRITEUNLOCK
:
212 SETUP_REQUEST(SMBwriteunlock
, 5, 3 + parms
->writeunlock
.in
.count
);
213 SSVAL(req
->out
.vwv
, VWV(0), parms
->writeunlock
.in
.file
.fnum
);
214 SSVAL(req
->out
.vwv
, VWV(1), parms
->writeunlock
.in
.count
);
215 SIVAL(req
->out
.vwv
, VWV(2), parms
->writeunlock
.in
.offset
);
216 SSVAL(req
->out
.vwv
, VWV(4), parms
->writeunlock
.in
.remaining
);
217 SCVAL(req
->out
.data
, 0, SMB_DATA_BLOCK
);
218 SSVAL(req
->out
.data
, 1, parms
->writeunlock
.in
.count
);
219 if (parms
->writeunlock
.in
.count
> 0) {
220 memcpy(req
->out
.data
+3, parms
->writeunlock
.in
.data
,
221 parms
->writeunlock
.in
.count
);
225 case RAW_WRITE_WRITE
:
226 SETUP_REQUEST(SMBwrite
, 5, 3 + parms
->write
.in
.count
);
227 SSVAL(req
->out
.vwv
, VWV(0), parms
->write
.in
.file
.fnum
);
228 SSVAL(req
->out
.vwv
, VWV(1), parms
->write
.in
.count
);
229 SIVAL(req
->out
.vwv
, VWV(2), parms
->write
.in
.offset
);
230 SSVAL(req
->out
.vwv
, VWV(4), parms
->write
.in
.remaining
);
231 SCVAL(req
->out
.data
, 0, SMB_DATA_BLOCK
);
232 SSVAL(req
->out
.data
, 1, parms
->write
.in
.count
);
233 if (parms
->write
.in
.count
> 0) {
234 memcpy(req
->out
.data
+3, parms
->write
.in
.data
, parms
->write
.in
.count
);
238 case RAW_WRITE_WRITECLOSE
:
239 SETUP_REQUEST(SMBwriteclose
, 6, 1 + parms
->writeclose
.in
.count
);
240 SSVAL(req
->out
.vwv
, VWV(0), parms
->writeclose
.in
.file
.fnum
);
241 SSVAL(req
->out
.vwv
, VWV(1), parms
->writeclose
.in
.count
);
242 SIVAL(req
->out
.vwv
, VWV(2), parms
->writeclose
.in
.offset
);
243 raw_push_dos_date3(tree
->session
->transport
,
244 req
->out
.vwv
, VWV(4), parms
->writeclose
.in
.mtime
);
245 SCVAL(req
->out
.data
, 0, 0);
246 if (parms
->writeclose
.in
.count
> 0) {
247 memcpy(req
->out
.data
+1, parms
->writeclose
.in
.data
,
248 parms
->writeclose
.in
.count
);
252 case RAW_WRITE_WRITEX
:
253 if (tree
->session
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
) {
256 SETUP_REQUEST(SMBwriteX
, bigoffset
? 14 : 12, parms
->writex
.in
.count
);
257 SSVAL(req
->out
.vwv
, VWV(0), SMB_CHAIN_NONE
);
258 SSVAL(req
->out
.vwv
, VWV(1), 0);
259 SSVAL(req
->out
.vwv
, VWV(2), parms
->writex
.in
.file
.fnum
);
260 SIVAL(req
->out
.vwv
, VWV(3), parms
->writex
.in
.offset
);
261 SIVAL(req
->out
.vwv
, VWV(5), 0); /* reserved */
262 SSVAL(req
->out
.vwv
, VWV(7), parms
->writex
.in
.wmode
);
263 SSVAL(req
->out
.vwv
, VWV(8), parms
->writex
.in
.remaining
);
264 SSVAL(req
->out
.vwv
, VWV(9), parms
->writex
.in
.count
>>16);
265 SSVAL(req
->out
.vwv
, VWV(10), parms
->writex
.in
.count
);
266 SSVAL(req
->out
.vwv
, VWV(11), PTR_DIFF(req
->out
.data
, req
->out
.hdr
));
268 SIVAL(req
->out
.vwv
,VWV(12),parms
->writex
.in
.offset
>>32);
270 if (parms
->writex
.in
.count
> 0) {
271 memcpy(req
->out
.data
, parms
->writex
.in
.data
, parms
->writex
.in
.count
);
275 case RAW_WRITE_SPLWRITE
:
276 SETUP_REQUEST(SMBsplwr
, 1, parms
->splwrite
.in
.count
);
277 SSVAL(req
->out
.vwv
, VWV(0), parms
->splwrite
.in
.file
.fnum
);
278 if (parms
->splwrite
.in
.count
> 0) {
279 memcpy(req
->out
.data
, parms
->splwrite
.in
.data
, parms
->splwrite
.in
.count
);
287 if (!smbcli_request_send(req
)) {
288 smbcli_request_destroy(req
);
296 /****************************************************************************
297 raw write interface (async recv)
298 ****************************************************************************/
299 _PUBLIC_ NTSTATUS
smb_raw_write_recv(struct smbcli_request
*req
, union smb_write
*parms
)
301 if (!smbcli_request_receive(req
) ||
302 !NT_STATUS_IS_OK(req
->status
)) {
306 switch (parms
->generic
.level
) {
307 case RAW_WRITE_WRITEUNLOCK
:
308 SMBCLI_CHECK_WCT(req
, 1);
309 parms
->writeunlock
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(0));
311 case RAW_WRITE_WRITE
:
312 SMBCLI_CHECK_WCT(req
, 1);
313 parms
->write
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(0));
315 case RAW_WRITE_WRITECLOSE
:
316 SMBCLI_CHECK_WCT(req
, 1);
317 parms
->writeclose
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(0));
319 case RAW_WRITE_WRITEX
:
320 SMBCLI_CHECK_WCT(req
, 6);
321 parms
->writex
.out
.nwritten
= SVAL(req
->in
.vwv
, VWV(2));
322 parms
->writex
.out
.nwritten
+= (CVAL(req
->in
.vwv
, VWV(4)) << 16);
323 parms
->writex
.out
.remaining
= SVAL(req
->in
.vwv
, VWV(3));
325 case RAW_WRITE_SPLWRITE
:
328 req
->status
= NT_STATUS_INTERNAL_ERROR
;
333 return smbcli_request_destroy(req
);
336 /****************************************************************************
337 raw write interface (sync interface)
338 ****************************************************************************/
339 _PUBLIC_ NTSTATUS
smb_raw_write(struct smbcli_tree
*tree
, union smb_write
*parms
)
341 struct smbcli_request
*req
= smb_raw_write_send(tree
, parms
);
342 return smb_raw_write_recv(req
, parms
);