00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "includes.h"
00022
00023
00024
00025
00026
00027 static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
00028 size_t size, int i)
00029 {
00030 BOOL bigoffset = False;
00031
00032 memset(cli->outbuf,'\0',smb_size);
00033 memset(cli->inbuf,'\0',smb_size);
00034
00035 if ((SMB_BIG_UINT)offset >> 32)
00036 bigoffset = True;
00037
00038 set_message(cli->outbuf,bigoffset ? 12 : 10,0,True);
00039
00040 SCVAL(cli->outbuf,smb_com,SMBreadX);
00041 SSVAL(cli->outbuf,smb_tid,cli->cnum);
00042 cli_setup_packet(cli);
00043
00044 SCVAL(cli->outbuf,smb_vwv0,0xFF);
00045 SSVAL(cli->outbuf,smb_vwv2,fnum);
00046 SIVAL(cli->outbuf,smb_vwv3,offset);
00047 SSVAL(cli->outbuf,smb_vwv5,size);
00048 SSVAL(cli->outbuf,smb_vwv6,size);
00049 SSVAL(cli->outbuf,smb_vwv7,((size >> 16) & 1));
00050 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
00051
00052 if (bigoffset) {
00053 SIVAL(cli->outbuf,smb_vwv10,(((SMB_BIG_UINT)offset)>>32) & 0xffffffff);
00054 }
00055
00056 return cli_send_smb(cli);
00057 }
00058
00059
00060
00061
00062
00063 ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
00064 {
00065 char *p;
00066 int size2;
00067 int readsize;
00068 ssize_t total = 0;
00069
00070 if (size == 0)
00071 return 0;
00072
00073
00074
00075
00076
00077
00078 if (cli->capabilities & CAP_LARGE_READX) {
00079 if (cli->is_samba) {
00080 readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
00081 } else {
00082 readsize = CLI_WINDOWS_MAX_LARGE_READX_SIZE;
00083 }
00084 } else {
00085 readsize = (cli->max_xmit - (smb_size+32)) & ~1023;
00086 }
00087
00088 while (total < size) {
00089 readsize = MIN(readsize, size-total);
00090
00091
00092
00093 if (!cli_issue_read(cli, fnum, offset, readsize, 0))
00094 return -1;
00095
00096 if (!cli_receive_smb(cli))
00097 return -1;
00098
00099
00100
00101
00102 if (cli_is_error(cli)) {
00103 BOOL recoverable_error = False;
00104 NTSTATUS status = NT_STATUS_OK;
00105 uint8 eclass = 0;
00106 uint32 ecode = 0;
00107
00108 if (cli_is_nt_error(cli))
00109 status = cli_nt_error(cli);
00110 else
00111 cli_dos_error(cli, &eclass, &ecode);
00112
00113
00114
00115
00116
00117
00118
00119 if ((eclass == ERRDOS && ecode == ERRmoredata) ||
00120 NT_STATUS_V(status) == NT_STATUS_V(STATUS_MORE_ENTRIES))
00121 recoverable_error = True;
00122
00123 if (!recoverable_error)
00124 return -1;
00125 }
00126
00127 size2 = SVAL(cli->inbuf, smb_vwv5);
00128 size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7) & 1)) << 16);
00129
00130 if (size2 > readsize) {
00131 DEBUG(5,("server returned more than we wanted!\n"));
00132 return -1;
00133 } else if (size2 < 0) {
00134 DEBUG(5,("read return < 0!\n"));
00135 return -1;
00136 }
00137
00138
00139
00140 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
00141 memcpy(buf + total, p, size2);
00142
00143 total += size2;
00144 offset += size2;
00145
00146
00147
00148
00149
00150 if (size2 < readsize)
00151 break;
00152 }
00153
00154 return total;
00155 }
00156
00157 #if 0
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 static BOOL cli_issue_readraw(struct cli_state *cli, int fnum, off_t offset,
00168 size_t size, int i)
00169 {
00170
00171 if (!cli->sign_info.use_smb_signing) {
00172 DEBUG(0, ("Cannot use readraw and SMB Signing\n"));
00173 return False;
00174 }
00175
00176 memset(cli->outbuf,'\0',smb_size);
00177 memset(cli->inbuf,'\0',smb_size);
00178
00179 set_message(cli->outbuf,10,0,True);
00180
00181 SCVAL(cli->outbuf,smb_com,SMBreadbraw);
00182 SSVAL(cli->outbuf,smb_tid,cli->cnum);
00183 cli_setup_packet(cli);
00184
00185 SSVAL(cli->outbuf,smb_vwv0,fnum);
00186 SIVAL(cli->outbuf,smb_vwv1,offset);
00187 SSVAL(cli->outbuf,smb_vwv2,size);
00188 SSVAL(cli->outbuf,smb_vwv3,size);
00189 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
00190
00191 return cli_send_smb(cli);
00192 }
00193
00194
00195
00196
00197
00198 ssize_t cli_readraw(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
00199 {
00200 char *p;
00201 int size2;
00202 size_t readsize;
00203 ssize_t total = 0;
00204
00205 if (size == 0)
00206 return 0;
00207
00208
00209
00210
00211
00212 readsize = 0xFFFF;
00213
00214 while (total < size) {
00215 readsize = MIN(readsize, size-total);
00216
00217
00218
00219 if (!cli_issue_readraw(cli, fnum, offset, readsize, 0))
00220 return -1;
00221
00222 if (!client_receive_smb(cli->fd, cli->inbuf, cli->timeout))
00223 return -1;
00224
00225 size2 = smb_len(cli->inbuf);
00226
00227 if (size2 > readsize) {
00228 DEBUG(5,("server returned more than we wanted!\n"));
00229 return -1;
00230 } else if (size2 < 0) {
00231 DEBUG(5,("read return < 0!\n"));
00232 return -1;
00233 }
00234
00235
00236
00237 if (size2) {
00238 p = cli->inbuf + 4;
00239 memcpy(buf + total, p, size2);
00240 }
00241
00242 total += size2;
00243 offset += size2;
00244
00245
00246
00247
00248
00249 if (size2 < readsize)
00250 break;
00251 }
00252
00253 return total;
00254 }
00255 #endif
00256
00257
00258
00259
00260 static BOOL cli_issue_write(struct cli_state *cli, int fnum, off_t offset,
00261 uint16 mode, const char *buf,
00262 size_t size, int i)
00263 {
00264 char *p;
00265 BOOL large_writex = False;
00266
00267 if (size > cli->bufsize) {
00268 cli->outbuf = (char *)SMB_REALLOC(cli->outbuf, size + 1024);
00269 if (!cli->outbuf) {
00270 return False;
00271 }
00272 cli->inbuf = (char *)SMB_REALLOC(cli->inbuf, size + 1024);
00273 if (cli->inbuf == NULL) {
00274 SAFE_FREE(cli->outbuf);
00275 return False;
00276 }
00277 cli->bufsize = size + 1024;
00278 }
00279
00280 memset(cli->outbuf,'\0',smb_size);
00281 memset(cli->inbuf,'\0',smb_size);
00282
00283 if (((SMB_BIG_UINT)offset >> 32) || (size > 0xFFFF)) {
00284 large_writex = True;
00285 }
00286
00287 if (large_writex)
00288 set_message(cli->outbuf,14,0,True);
00289 else
00290 set_message(cli->outbuf,12,0,True);
00291
00292 SCVAL(cli->outbuf,smb_com,SMBwriteX);
00293 SSVAL(cli->outbuf,smb_tid,cli->cnum);
00294 cli_setup_packet(cli);
00295
00296 SCVAL(cli->outbuf,smb_vwv0,0xFF);
00297 SSVAL(cli->outbuf,smb_vwv2,fnum);
00298
00299 SIVAL(cli->outbuf,smb_vwv3,offset);
00300 SIVAL(cli->outbuf,smb_vwv5,0);
00301 SSVAL(cli->outbuf,smb_vwv7,mode);
00302
00303 SSVAL(cli->outbuf,smb_vwv8,(mode & 0x0008) ? size : 0);
00304
00305
00306
00307
00308
00309
00310 SSVAL(cli->outbuf,smb_vwv9,((size>>16)&1));
00311 SSVAL(cli->outbuf,smb_vwv10,size);
00312 SSVAL(cli->outbuf,smb_vwv11,
00313 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
00314
00315 if (large_writex) {
00316 SIVAL(cli->outbuf,smb_vwv12,(((SMB_BIG_UINT)offset)>>32) & 0xffffffff);
00317 }
00318
00319 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
00320 memcpy(p, buf, size);
00321 cli_setup_bcc(cli, p+size);
00322
00323 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
00324
00325 show_msg(cli->outbuf);
00326 return cli_send_smb(cli);
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337 ssize_t cli_write(struct cli_state *cli,
00338 int fnum, uint16 write_mode,
00339 const char *buf, off_t offset, size_t size)
00340 {
00341 ssize_t bwritten = 0;
00342 unsigned int issued = 0;
00343 unsigned int received = 0;
00344 int mpx = 1;
00345 int block = cli->max_xmit - (smb_size+32);
00346 int blocks = (size + (block-1)) / block;
00347
00348 if(cli->max_mux > 1) {
00349 mpx = cli->max_mux-1;
00350 } else {
00351 mpx = 1;
00352 }
00353
00354 while (received < blocks) {
00355 ssize_t size1 = 0;
00356
00357 while ((issued - received < mpx) && (issued < blocks)) {
00358 ssize_t bsent = issued * block;
00359
00360 size1 = MIN(block, size - bsent);
00361
00362 if (!cli_issue_write(cli, fnum, offset + bsent,
00363 write_mode,
00364 buf + bsent,
00365 size1, issued))
00366 return -1;
00367 issued++;
00368 }
00369
00370 if (!cli_receive_smb(cli))
00371 return bwritten;
00372
00373 received++;
00374
00375 if (cli_is_error(cli))
00376 break;
00377
00378 bwritten += SVAL(cli->inbuf, smb_vwv2);
00379 if (size1 > 0xFFFF) {
00380 bwritten += (((int)(SVAL(cli->inbuf, smb_vwv4)))<<16);
00381 }
00382 }
00383
00384 while (received < issued && cli_receive_smb(cli))
00385 received++;
00386
00387 return bwritten;
00388 }
00389
00390
00391
00392
00393
00394 ssize_t cli_smbwrite(struct cli_state *cli,
00395 int fnum, char *buf, off_t offset, size_t size1)
00396 {
00397 char *p;
00398 ssize_t total = 0;
00399
00400 do {
00401 size_t size = MIN(size1, cli->max_xmit - 48);
00402
00403 memset(cli->outbuf,'\0',smb_size);
00404 memset(cli->inbuf,'\0',smb_size);
00405
00406 set_message(cli->outbuf,5, 0,True);
00407
00408 SCVAL(cli->outbuf,smb_com,SMBwrite);
00409 SSVAL(cli->outbuf,smb_tid,cli->cnum);
00410 cli_setup_packet(cli);
00411
00412 SSVAL(cli->outbuf,smb_vwv0,fnum);
00413 SSVAL(cli->outbuf,smb_vwv1,size);
00414 SIVAL(cli->outbuf,smb_vwv2,offset);
00415 SSVAL(cli->outbuf,smb_vwv4,0);
00416
00417 p = smb_buf(cli->outbuf);
00418 *p++ = 1;
00419 SSVAL(p, 0, size); p += 2;
00420 memcpy(p, buf + total, size); p += size;
00421
00422 cli_setup_bcc(cli, p);
00423
00424 if (!cli_send_smb(cli))
00425 return -1;
00426
00427 if (!cli_receive_smb(cli))
00428 return -1;
00429
00430 if (cli_is_error(cli))
00431 return -1;
00432
00433 size = SVAL(cli->inbuf,smb_vwv0);
00434 if (size == 0)
00435 break;
00436
00437 size1 -= size;
00438 total += size;
00439 offset += size;
00440
00441 } while (size1);
00442
00443 return total;
00444 }