2 Unix SMB/Netbios implementation.
4 client file read/write routines
5 Copyright (C) Andrew Tridgell 1994-1998
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /****************************************************************************
27 issue a single SMBread and don't wait for a reply
28 ****************************************************************************/
29 static void cli_issue_read(struct cli_state
*cli
, int fnum
, off_t offset
,
32 memset(cli
->outbuf
,'\0',smb_size
);
33 memset(cli
->inbuf
,'\0',smb_size
);
35 set_message(cli
->outbuf
,10,0,True
);
37 CVAL(cli
->outbuf
,smb_com
) = SMBreadX
;
38 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
39 cli_setup_packet(cli
);
41 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
42 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
43 SIVAL(cli
->outbuf
,smb_vwv3
,offset
);
44 SSVAL(cli
->outbuf
,smb_vwv5
,size
);
45 SSVAL(cli
->outbuf
,smb_vwv6
,size
);
46 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
+ i
);
51 /****************************************************************************
53 ****************************************************************************/
54 size_t cli_read(struct cli_state
*cli
, int fnum
, char *buf
, off_t offset
, size_t size
)
61 * There is a problem in this code when mpx is more than one.
62 * for some reason files can get corrupted when being read.
63 * Until we understand this fully I am serializing reads (one
64 * read/one reply) for now. JRA.
67 int mpx
= MAX(cli
->max_mux
-1, 1);
71 int block
= (cli
->max_xmit
- (smb_size
+32)) & ~1023;
73 int blocks
= (size
+ (block
-1)) / block
;
75 if (size
== 0) return 0;
77 while (received
< blocks
) {
80 while (issued
- received
< mpx
&& issued
< blocks
) {
81 int size1
= MIN(block
, size
-issued
*block
);
82 cli_issue_read(cli
, fnum
, offset
+issued
*block
, size1
, issued
);
86 if (!cli_receive_smb(cli
)) {
91 mid
= SVAL(cli
->inbuf
, smb_mid
) - cli
->mid
;
92 size2
= SVAL(cli
->inbuf
, smb_vwv5
);
94 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
95 blocks
= MIN(blocks
, mid
-1);
100 blocks
= MIN(blocks
, mid
-1);
101 /* this distinguishes EOF from an error */
102 total
= MAX(total
, 0);
107 DEBUG(0,("server returned more than we wanted!\n"));
111 DEBUG(0,("invalid mid from server!\n"));
114 p
= smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_vwv6
);
116 memcpy(buf
+mid
*block
, p
, size2
);
118 total
= MAX(total
, mid
*block
+ size2
);
121 while (received
< issued
) {
122 cli_receive_smb(cli
);
130 /****************************************************************************
131 issue a single SMBwrite and don't wait for a reply
132 ****************************************************************************/
133 static void cli_issue_write(struct cli_state
*cli
, int fnum
, off_t offset
, uint16 mode
, char *buf
,
138 memset(cli
->outbuf
,'\0',smb_size
);
139 memset(cli
->inbuf
,'\0',smb_size
);
141 set_message(cli
->outbuf
,12,size
,True
);
143 CVAL(cli
->outbuf
,smb_com
) = SMBwriteX
;
144 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
145 cli_setup_packet(cli
);
147 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
148 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
150 SIVAL(cli
->outbuf
,smb_vwv3
,offset
);
151 SIVAL(cli
->outbuf
,smb_vwv5
,IS_BITS_SET_ALL(mode
, 0x0008) ? 0xFFFFFFFF : 0);
152 SSVAL(cli
->outbuf
,smb_vwv7
,mode
);
154 SSVAL(cli
->outbuf
,smb_vwv8
,IS_BITS_SET_ALL(mode
, 0x0008) ? size
: 0);
155 SSVAL(cli
->outbuf
,smb_vwv10
,size
);
156 SSVAL(cli
->outbuf
,smb_vwv11
,
157 smb_buf(cli
->outbuf
) - smb_base(cli
->outbuf
));
159 p
= smb_base(cli
->outbuf
) + SVAL(cli
->outbuf
,smb_vwv11
);
160 memcpy(p
, buf
, size
);
162 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
+ i
);
164 show_msg(cli
->outbuf
);
168 /****************************************************************************
170 write_mode: 0x0001 disallow write cacheing
171 0x0002 return bytes remaining
172 0x0004 use raw named pipe protocol
173 0x0008 start of message mode named pipe protocol
174 ****************************************************************************/
175 ssize_t
cli_write(struct cli_state
*cli
,
176 int fnum
, uint16 write_mode
,
177 char *buf
, off_t offset
, size_t size
)
182 int mpx
= MAX(cli
->max_mux
-1, 1);
183 int block
= (cli
->max_xmit
- (smb_size
+32)) & ~1023;
184 int blocks
= (size
+ (block
-1)) / block
;
186 while (received
< blocks
) {
188 while ((issued
- received
< mpx
) && (issued
< blocks
))
190 int bsent
= issued
* block
;
191 int size1
= MIN(block
, size
- bsent
);
193 cli_issue_write(cli
, fnum
, offset
+ bsent
,
200 if (!cli_receive_smb(cli
))
207 if (CVAL(cli
->inbuf
,smb_rcls
) != 0)
212 bwritten
+= SVAL(cli
->inbuf
, smb_vwv2
);
215 while (received
< issued
&& cli_receive_smb(cli
))
224 /****************************************************************************
225 write to a file using a SMBwrite and not bypassing 0 byte writes
226 ****************************************************************************/
227 ssize_t
cli_smbwrite(struct cli_state
*cli
,
228 int fnum
, char *buf
, off_t offset
, size_t size1
)
234 size_t size
= MIN(size1
, cli
->max_xmit
- 48);
236 memset(cli
->outbuf
,'\0',smb_size
);
237 memset(cli
->inbuf
,'\0',smb_size
);
239 set_message(cli
->outbuf
,5, 3 + size
,True
);
241 CVAL(cli
->outbuf
,smb_com
) = SMBwrite
;
242 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
243 cli_setup_packet(cli
);
245 SSVAL(cli
->outbuf
,smb_vwv0
,fnum
);
246 SSVAL(cli
->outbuf
,smb_vwv1
,size
);
247 SIVAL(cli
->outbuf
,smb_vwv2
,offset
);
248 SSVAL(cli
->outbuf
,smb_vwv4
,0);
250 p
= smb_buf(cli
->outbuf
);
253 memcpy(p
+2, buf
, size
);
256 if (!cli_receive_smb(cli
)) {
260 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
264 size
= SVAL(cli
->inbuf
,smb_vwv0
);
265 if (size
== 0) break;