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 ****************************************************************************/
30 static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
33 memset(cli->outbuf,'\0',smb_size);
34 memset(cli->inbuf,'\0',smb_size);
36 set_message(cli->outbuf,10,0,True);
38 CVAL(cli->outbuf,smb_com) = SMBreadX;
39 SSVAL(cli->outbuf,smb_tid,cli->cnum);
40 cli_setup_packet(cli);
42 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
43 SSVAL(cli->outbuf,smb_vwv2,fnum);
44 SIVAL(cli->outbuf,smb_vwv3,offset);
45 SSVAL(cli->outbuf,smb_vwv5,size);
46 SSVAL(cli->outbuf,smb_vwv6,size);
47 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
49 return cli_send_smb(cli);
52 /****************************************************************************
53 Read size bytes at offset offset using SMBreadX.
54 ****************************************************************************/
56 ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
69 * Set readsize to the maximum size we can handle in one readX,
70 * rounded down to a multiple of 1024.
73 readsize = (cli->max_xmit - (smb_size+32)) & ~1023;
75 while (total < size) {
76 readsize = MIN(readsize, size-total);
78 /* Issue a read and receive a reply */
80 if (!cli_issue_read(cli, fnum, offset, readsize, 0))
83 if (!cli_receive_smb(cli))
87 * Check for error. Because the client library doesn't support
88 * STATUS32, we need to check for and ignore the more data error
92 if (cli_error(cli, &eclass, &ecode, NULL) &&
93 (eclass != ERRDOS && ecode != ERRmoredata)) {
97 size2 = SVAL(cli->inbuf, smb_vwv5);
99 if (size2 > readsize) {
100 DEBUG(5,("server returned more than we wanted!\n"));
102 } else if (size2 < 0) {
103 DEBUG(5,("read return < 0!\n"));
107 /* Copy data into buffer */
109 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
110 memcpy(buf + total, p, size2);
116 * If the server returned less than we asked for we're at EOF.
119 if (size2 < readsize)
126 /****************************************************************************
127 issue a single SMBwrite and don't wait for a reply
128 ****************************************************************************/
130 static BOOL cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
135 memset(cli->outbuf,'\0',smb_size);
136 memset(cli->inbuf,'\0',smb_size);
139 set_message(cli->outbuf,14,0,True);
141 set_message(cli->outbuf,12,0,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,(mode & 0x0008) ? 0xFFFFFFFF : 0);
152 SSVAL(cli->outbuf,smb_vwv7,mode);
154 SSVAL(cli->outbuf,smb_vwv8,(mode & 0x0008) ? size : 0);
155 SSVAL(cli->outbuf,smb_vwv9,((size>>16)&1));
156 SSVAL(cli->outbuf,smb_vwv10,size);
157 SSVAL(cli->outbuf,smb_vwv11,
158 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
160 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
161 memcpy(p, buf, size);
162 cli_setup_bcc(cli, p+size);
164 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
166 show_msg(cli->outbuf);
167 return cli_send_smb(cli);
170 /****************************************************************************
172 write_mode: 0x0001 disallow write cacheing
173 0x0002 return bytes remaining
174 0x0004 use raw named pipe protocol
175 0x0008 start of message mode named pipe protocol
176 ****************************************************************************/
178 ssize_t cli_write(struct cli_state *cli,
179 int fnum, uint16 write_mode,
180 char *buf, off_t offset, size_t size)
185 int mpx = MAX(cli->max_mux-1, 1);
186 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
187 int blocks = (size + (block-1)) / block;
189 while (received < blocks) {
191 while ((issued - received < mpx) && (issued < blocks)) {
192 int bsent = issued * block;
193 int size1 = MIN(block, size - bsent);
195 if (!cli_issue_write(cli, fnum, offset + bsent,
203 if (!cli_receive_smb(cli))
208 if (CVAL(cli->inbuf,smb_rcls) != 0)
211 bwritten += SVAL(cli->inbuf, smb_vwv2);
214 while (received < issued && cli_receive_smb(cli))
220 /****************************************************************************
221 write to a file using a SMBwrite and not bypassing 0 byte writes
222 ****************************************************************************/
224 ssize_t cli_smbwrite(struct cli_state *cli,
225 int fnum, char *buf, off_t offset, size_t size1)
231 size_t size = MIN(size1, cli->max_xmit - 48);
233 memset(cli->outbuf,'\0',smb_size);
234 memset(cli->inbuf,'\0',smb_size);
236 set_message(cli->outbuf,5, 0,True);
238 CVAL(cli->outbuf,smb_com) = SMBwrite;
239 SSVAL(cli->outbuf,smb_tid,cli->cnum);
240 cli_setup_packet(cli);
242 SSVAL(cli->outbuf,smb_vwv0,fnum);
243 SSVAL(cli->outbuf,smb_vwv1,size);
244 SIVAL(cli->outbuf,smb_vwv2,offset);
245 SSVAL(cli->outbuf,smb_vwv4,0);
247 p = smb_buf(cli->outbuf);
249 SSVAL(p, 0, size); p += 2;
250 memcpy(p, buf, size); p += size;
252 cli_setup_bcc(cli, p);
254 if (!cli_send_smb(cli))
257 if (!cli_receive_smb(cli))
260 if (CVAL(cli->inbuf,smb_rcls) != 0)
263 size = SVAL(cli->inbuf,smb_vwv0);