1/* 2 Unix SMB/CIFS implementation. 3 client file read/write routines 4 Copyright (C) Andrew Tridgell 1994-1998 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21 22/**************************************************************************** 23 Calculate the recommended read buffer size 24****************************************************************************/ 25static size_t cli_read_max_bufsize(struct cli_state *cli) 26{ 27 if (!client_is_signing_on(cli) && !cli_encryption_on(cli) 28 && (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { 29 return CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE; 30 } 31 if (cli->capabilities & CAP_LARGE_READX) { 32 return cli->is_samba 33 ? CLI_SAMBA_MAX_LARGE_READX_SIZE 34 : CLI_WINDOWS_MAX_LARGE_READX_SIZE; 35 } 36 return (cli->max_xmit - (smb_size+32)) & ~1023; 37} 38 39/**************************************************************************** 40 Calculate the recommended write buffer size 41****************************************************************************/ 42static size_t cli_write_max_bufsize(struct cli_state *cli, uint16_t write_mode) 43{ 44 if (write_mode == 0 && 45 !client_is_signing_on(cli) && 46 !cli_encryption_on(cli) && 47 (cli->posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) && 48 (cli->capabilities & CAP_LARGE_FILES)) { 49 /* Only do massive writes if we can do them direct 50 * with no signing or encrypting - not on a pipe. */ 51 return CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE; 52 } 53 54 if (cli->is_samba) { 55 return CLI_SAMBA_MAX_LARGE_WRITEX_SIZE; 56 } 57 58 if (((cli->capabilities & CAP_LARGE_WRITEX) == 0) 59 || client_is_signing_on(cli) 60 || strequal(cli->dev, "LPT1:")) { 61 62 /* 63 * Printer devices are restricted to max_xmit writesize in 64 * Vista and XPSP3 as are signing connections. 65 */ 66 67 return (cli->max_xmit - (smb_size+32)) & ~1023; 68 } 69 70 return CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE; 71} 72 73struct cli_read_andx_state { 74 size_t size; 75 uint16_t vwv[12]; 76 NTSTATUS status; 77 size_t received; 78 uint8_t *buf; 79}; 80 81static void cli_read_andx_done(struct tevent_req *subreq); 82 83struct tevent_req *cli_read_andx_create(TALLOC_CTX *mem_ctx, 84 struct event_context *ev, 85 struct cli_state *cli, uint16_t fnum, 86 off_t offset, size_t size, 87 struct tevent_req **psmbreq) 88{ 89 struct tevent_req *req, *subreq; 90 struct cli_read_andx_state *state; 91 uint8_t wct = 10; 92 93 if (size > cli_read_max_bufsize(cli)) { 94 DEBUG(0, ("cli_read_andx_send got size=%d, can only handle " 95 "size=%d\n", (int)size, 96 (int)cli_read_max_bufsize(cli))); 97 return NULL; 98 } 99 100 req = tevent_req_create(mem_ctx, &state, struct cli_read_andx_state); 101 if (req == NULL) { 102 return NULL; 103 } 104 state->size = size; 105 106 SCVAL(state->vwv + 0, 0, 0xFF); 107 SCVAL(state->vwv + 0, 1, 0); 108 SSVAL(state->vwv + 1, 0, 0); 109 SSVAL(state->vwv + 2, 0, fnum); 110 SIVAL(state->vwv + 3, 0, offset); 111 SSVAL(state->vwv + 5, 0, size); 112 SSVAL(state->vwv + 6, 0, size); 113 SSVAL(state->vwv + 7, 0, (size >> 16)); 114 SSVAL(state->vwv + 8, 0, 0); 115 SSVAL(state->vwv + 9, 0, 0); 116 117 if (cli->capabilities & CAP_LARGE_FILES) { 118 SIVAL(state->vwv + 10, 0, 119 (((uint64_t)offset)>>32) & 0xffffffff); 120 wct = 12; 121 } else { 122 if ((((uint64_t)offset) & 0xffffffff00000000LL) != 0) { 123 DEBUG(10, ("cli_read_andx_send got large offset where " 124 "the server does not support it\n")); 125 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); 126 return tevent_req_post(req, ev); 127 } 128 } 129 130 subreq = cli_smb_req_create(state, ev, cli, SMBreadX, 0, wct, 131 state->vwv, 0, NULL); 132 if (subreq == NULL) { 133 TALLOC_FREE(req); 134 return NULL; 135 } 136 tevent_req_set_callback(subreq, cli_read_andx_done, req); 137 *psmbreq = subreq; 138 return req; 139} 140 141struct tevent_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, 142 struct event_context *ev, 143 struct cli_state *cli, uint16_t fnum, 144 off_t offset, size_t size) 145{ 146 struct tevent_req *req, *subreq; 147 NTSTATUS status; 148 149 req = cli_read_andx_create(mem_ctx, ev, cli, fnum, offset, size, 150 &subreq); 151 if (req == NULL) { 152 return NULL; 153 } 154 155 status = cli_smb_req_send(subreq); 156 if (!NT_STATUS_IS_OK(status)) { 157 tevent_req_nterror(req, status); 158 return tevent_req_post(req, ev); 159 } 160 return req; 161} 162 163static void cli_read_andx_done(struct tevent_req *subreq) 164{ 165 struct tevent_req *req = tevent_req_callback_data( 166 subreq, struct tevent_req); 167 struct cli_read_andx_state *state = tevent_req_data( 168 req, struct cli_read_andx_state); 169 uint8_t *inbuf; 170 uint8_t wct; 171 uint16_t *vwv; 172 uint32_t num_bytes; 173 uint8_t *bytes; 174 175 state->status = cli_smb_recv(subreq, 12, &wct, &vwv, &num_bytes, 176 &bytes); 177 if (NT_STATUS_IS_ERR(state->status)) { 178 tevent_req_nterror(req, state->status); 179 return; 180 } 181 182 /* size is the number of bytes the server returned. 183 * Might be zero. */ 184 state->received = SVAL(vwv + 5, 0); 185 state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16); 186 187 if (state->received > state->size) { 188 DEBUG(5,("server returned more than we wanted!\n")); 189 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR); 190 return; 191 } 192 193 /* 194 * bcc field must be valid for small reads, for large reads the 16-bit 195 * bcc field can't be correct. 196 */ 197 198 if ((state->received < 0xffff) && (state->received > num_bytes)) { 199 DEBUG(5, ("server announced more bytes than sent\n")); 200 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); 201 return; 202 } 203 204 inbuf = cli_smb_inbuf(subreq); 205 state->buf = (uint8_t *)smb_base(inbuf) + SVAL(vwv+6, 0); 206 207 if (trans_oob(smb_len(inbuf), SVAL(vwv+6, 0), state->received) 208 || ((state->received != 0) && (state->buf < bytes))) { 209 DEBUG(5, ("server returned invalid read&x data offset\n")); 210 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); 211 return; 212 } 213 tevent_req_done(req); 214} 215 216/* 217 * Pull the data out of a finished async read_and_x request. rcvbuf is 218 * talloced from the request, so better make sure that you copy it away before 219 * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not 220 * talloc_move it! 221 */ 222 223NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received, 224 uint8_t **rcvbuf) 225{ 226 struct cli_read_andx_state *state = tevent_req_data( 227 req, struct cli_read_andx_state); 228 NTSTATUS status; 229 230 if (tevent_req_is_nterror(req, &status)) { 231 return status; 232 } 233 *received = state->received; 234 *rcvbuf = state->buf; 235 return NT_STATUS_OK; 236} 237 238struct cli_readall_state { 239 struct tevent_context *ev; 240 struct cli_state *cli; 241 uint16_t fnum; 242 off_t start_offset; 243 size_t size; 244 size_t received; 245 uint8_t *buf; 246}; 247 248static void cli_readall_done(struct tevent_req *subreq); 249 250static struct tevent_req *cli_readall_send(TALLOC_CTX *mem_ctx, 251 struct event_context *ev, 252 struct cli_state *cli, 253 uint16_t fnum, 254 off_t offset, size_t size) 255{ 256 struct tevent_req *req, *subreq; 257 struct cli_readall_state *state; 258 259 req = tevent_req_create(mem_ctx, &state, struct cli_readall_state); 260 if (req == NULL) { 261 return NULL; 262 } 263 state->ev = ev; 264 state->cli = cli; 265 state->fnum = fnum; 266 state->start_offset = offset; 267 state->size = size; 268 state->received = 0; 269 state->buf = NULL; 270 271 subreq = cli_read_andx_send(state, ev, cli, fnum, offset, size); 272 if (tevent_req_nomem(subreq, req)) { 273 return tevent_req_post(req, ev); 274 } 275 tevent_req_set_callback(subreq, cli_readall_done, req); 276 return req; 277} 278 279static void cli_readall_done(struct tevent_req *subreq) 280{ 281 struct tevent_req *req = tevent_req_callback_data( 282 subreq, struct tevent_req); 283 struct cli_readall_state *state = tevent_req_data( 284 req, struct cli_readall_state); 285 ssize_t received; 286 uint8_t *buf; 287 NTSTATUS status; 288 289 status = cli_read_andx_recv(subreq, &received, &buf); 290 if (!NT_STATUS_IS_OK(status)) { 291 tevent_req_nterror(req, status); 292 return; 293 } 294 295 if (received == 0) { 296 /* EOF */ 297 tevent_req_done(req); 298 return; 299 } 300 301 if ((state->received == 0) && (received == state->size)) { 302 /* Ideal case: Got it all in one run */ 303 state->buf = buf; 304 state->received += received; 305 tevent_req_done(req); 306 return; 307 } 308 309 /* 310 * We got a short read, issue a read for the 311 * rest. Unfortunately we have to allocate the buffer 312 * ourselves now, as our caller expects to receive a single 313 * buffer. cli_read_andx does it from the buffer received from 314 * the net, but with a short read we have to put it together 315 * from several reads. 316 */ 317 318 if (state->buf == NULL) { 319 state->buf = talloc_array(state, uint8_t, state->size); 320 if (tevent_req_nomem(state->buf, req)) { 321 return; 322 } 323 } 324 memcpy(state->buf + state->received, buf, received); 325 state->received += received; 326 327 TALLOC_FREE(subreq); 328 329 if (state->received >= state->size) { 330 tevent_req_done(req); 331 return; 332 } 333 334 subreq = cli_read_andx_send(state, state->ev, state->cli, state->fnum, 335 state->start_offset + state->received, 336 state->size - state->received); 337 if (tevent_req_nomem(subreq, req)) { 338 return; 339 } 340 tevent_req_set_callback(subreq, cli_readall_done, req); 341} 342 343static NTSTATUS cli_readall_recv(struct tevent_req *req, ssize_t *received, 344 uint8_t **rcvbuf) 345{ 346 struct cli_readall_state *state = tevent_req_data( 347 req, struct cli_readall_state); 348 NTSTATUS status; 349 350 if (tevent_req_is_nterror(req, &status)) { 351 return status; 352 } 353 *received = state->received; 354 *rcvbuf = state->buf; 355 return NT_STATUS_OK; 356} 357 358struct cli_pull_subreq { 359 struct tevent_req *req; 360 ssize_t received; 361 uint8_t *buf; 362}; 363 364/* 365 * Parallel read support. 366 * 367 * cli_pull sends as many read&x requests as the server would allow via 368 * max_mux at a time. When replies flow back in, the data is written into 369 * the callback function "sink" in the right order. 370 */ 371 372struct cli_pull_state { 373 struct tevent_req *req; 374 375 struct event_context *ev; 376 struct cli_state *cli; 377 uint16_t fnum; 378 off_t start_offset; 379 SMB_OFF_T size; 380 381 NTSTATUS (*sink)(char *buf, size_t n, void *priv); 382 void *priv; 383 384 size_t chunk_size; 385 386 /* 387 * Outstanding requests 388 */ 389 int num_reqs; 390 struct cli_pull_subreq *reqs; 391 392 /* 393 * For how many bytes did we send requests already? 394 */ 395 SMB_OFF_T requested; 396 397 /* 398 * Next request index to push into "sink". This walks around the "req" 399 * array, taking care that the requests are pushed to "sink" in the 400 * right order. If necessary (i.e. replies don't come in in the right 401 * order), replies are held back in "reqs". 402 */ 403 int top_req; 404 405 /* 406 * How many bytes did we push into "sink"? 407 */ 408 409 SMB_OFF_T pushed; 410}; 411 412static char *cli_pull_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) 413{ 414 struct cli_pull_state *state = tevent_req_data( 415 req, struct cli_pull_state); 416 char *result; 417 418 result = tevent_req_print(mem_ctx, req); 419 if (result == NULL) { 420 return NULL; 421 } 422 423 return talloc_asprintf_append_buffer( 424 result, "num_reqs=%d, top_req=%d", 425 state->num_reqs, state->top_req); 426} 427 428static void cli_pull_read_done(struct tevent_req *read_req); 429 430/* 431 * Prepare an async pull request 432 */ 433 434struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, 435 struct event_context *ev, 436 struct cli_state *cli, 437 uint16_t fnum, off_t start_offset, 438 SMB_OFF_T size, size_t window_size, 439 NTSTATUS (*sink)(char *buf, size_t n, 440 void *priv), 441 void *priv) 442{ 443 struct tevent_req *req; 444 struct cli_pull_state *state; 445 int i; 446 447 req = tevent_req_create(mem_ctx, &state, struct cli_pull_state); 448 if (req == NULL) { 449 return NULL; 450 } 451 tevent_req_set_print_fn(req, cli_pull_print); 452 state->req = req; 453 454 state->cli = cli; 455 state->ev = ev; 456 state->fnum = fnum; 457 state->start_offset = start_offset; 458 state->size = size; 459 state->sink = sink; 460 state->priv = priv; 461 462 state->pushed = 0; 463 state->top_req = 0; 464 465 if (size == 0) { 466 tevent_req_done(req); 467 return tevent_req_post(req, ev); 468 } 469 470 state->chunk_size = cli_read_max_bufsize(cli); 471 472 state->num_reqs = MAX(window_size/state->chunk_size, 1); 473 state->num_reqs = MIN(state->num_reqs, cli->max_mux); 474 475 state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_pull_subreq, 476 state->num_reqs); 477 if (state->reqs == NULL) { 478 goto failed; 479 } 480 481 state->requested = 0; 482 483 for (i=0; i<state->num_reqs; i++) { 484 struct cli_pull_subreq *subreq = &state->reqs[i]; 485 SMB_OFF_T size_left; 486 size_t request_thistime; 487 488 if (state->requested >= size) { 489 state->num_reqs = i; 490 break; 491 } 492 493 size_left = size - state->requested; 494 request_thistime = MIN(size_left, state->chunk_size); 495 496 subreq->req = cli_readall_send( 497 state->reqs, ev, cli, fnum, 498 state->start_offset + state->requested, 499 request_thistime); 500 501 if (subreq->req == NULL) { 502 goto failed; 503 } 504 tevent_req_set_callback(subreq->req, cli_pull_read_done, req); 505 state->requested += request_thistime; 506 } 507 return req; 508 509failed: 510 TALLOC_FREE(req); 511 return NULL; 512} 513 514/* 515 * Handle incoming read replies, push the data into sink and send out new 516 * requests if necessary. 517 */ 518 519static void cli_pull_read_done(struct tevent_req *subreq) 520{ 521 struct tevent_req *req = tevent_req_callback_data( 522 subreq, struct tevent_req); 523 struct cli_pull_state *state = tevent_req_data( 524 req, struct cli_pull_state); 525 struct cli_pull_subreq *pull_subreq = NULL; 526 NTSTATUS status; 527 int i; 528 529 for (i = 0; i < state->num_reqs; i++) { 530 pull_subreq = &state->reqs[i]; 531 if (subreq == pull_subreq->req) { 532 break; 533 } 534 } 535 if (i == state->num_reqs) { 536 /* Huh -- received something we did not send?? */ 537 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 538 return; 539 } 540 541 status = cli_readall_recv(subreq, &pull_subreq->received, 542 &pull_subreq->buf); 543 if (!NT_STATUS_IS_OK(status)) { 544 tevent_req_nterror(state->req, status); 545 return; 546 } 547 548 /* 549 * This loop is the one to take care of out-of-order replies. All 550 * pending requests are in state->reqs, state->reqs[top_req] is the 551 * one that is to be pushed next. If however a request later than 552 * top_req is replied to, then we can't push yet. If top_req is 553 * replied to at a later point then, we need to push all the finished 554 * requests. 555 */ 556 557 while (state->reqs[state->top_req].req != NULL) { 558 struct cli_pull_subreq *top_subreq; 559 560 DEBUG(11, ("cli_pull_read_done: top_req = %d\n", 561 state->top_req)); 562 563 top_subreq = &state->reqs[state->top_req]; 564 565 if (tevent_req_is_in_progress(top_subreq->req)) { 566 DEBUG(11, ("cli_pull_read_done: top request not yet " 567 "done\n")); 568 return; 569 } 570 571 DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already " 572 "pushed\n", (int)top_subreq->received, 573 (int)state->pushed)); 574 575 status = state->sink((char *)top_subreq->buf, 576 top_subreq->received, state->priv); 577 if (!NT_STATUS_IS_OK(status)) { 578 tevent_req_nterror(state->req, status); 579 return; 580 } 581 state->pushed += top_subreq->received; 582 583 TALLOC_FREE(state->reqs[state->top_req].req); 584 585 if (state->requested < state->size) { 586 struct tevent_req *new_req; 587 SMB_OFF_T size_left; 588 size_t request_thistime; 589 590 size_left = state->size - state->requested; 591 request_thistime = MIN(size_left, state->chunk_size); 592 593 DEBUG(10, ("cli_pull_read_done: Requesting %d bytes " 594 "at %d, position %d\n", 595 (int)request_thistime, 596 (int)(state->start_offset 597 + state->requested), 598 state->top_req)); 599 600 new_req = cli_readall_send( 601 state->reqs, state->ev, state->cli, 602 state->fnum, 603 state->start_offset + state->requested, 604 request_thistime); 605 606 if (tevent_req_nomem(new_req, state->req)) { 607 return; 608 } 609 tevent_req_set_callback(new_req, cli_pull_read_done, 610 req); 611 612 state->reqs[state->top_req].req = new_req; 613 state->requested += request_thistime; 614 } 615 616 state->top_req = (state->top_req+1) % state->num_reqs; 617 } 618 619 tevent_req_done(req); 620} 621 622NTSTATUS cli_pull_recv(struct tevent_req *req, SMB_OFF_T *received) 623{ 624 struct cli_pull_state *state = tevent_req_data( 625 req, struct cli_pull_state); 626 NTSTATUS status; 627 628 if (tevent_req_is_nterror(req, &status)) { 629 return status; 630 } 631 *received = state->pushed; 632 return NT_STATUS_OK; 633} 634 635NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, 636 off_t start_offset, SMB_OFF_T size, size_t window_size, 637 NTSTATUS (*sink)(char *buf, size_t n, void *priv), 638 void *priv, SMB_OFF_T *received) 639{ 640 TALLOC_CTX *frame = talloc_stackframe(); 641 struct event_context *ev; 642 struct tevent_req *req; 643 NTSTATUS status = NT_STATUS_OK; 644 645 if (cli_has_async_calls(cli)) { 646 /* 647 * Can't use sync call while an async call is in flight 648 */ 649 status = NT_STATUS_INVALID_PARAMETER; 650 goto fail; 651 } 652 653 ev = event_context_init(frame); 654 if (ev == NULL) { 655 status = NT_STATUS_NO_MEMORY; 656 goto fail; 657 } 658 659 req = cli_pull_send(frame, ev, cli, fnum, start_offset, size, 660 window_size, sink, priv); 661 if (req == NULL) { 662 status = NT_STATUS_NO_MEMORY; 663 goto fail; 664 } 665 666 if (!tevent_req_poll(req, ev)) { 667 status = map_nt_error_from_unix(errno); 668 goto fail; 669 } 670 671 status = cli_pull_recv(req, received); 672 fail: 673 TALLOC_FREE(frame); 674 if (!NT_STATUS_IS_OK(status)) { 675 cli_set_error(cli, status); 676 } 677 return status; 678} 679 680static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv) 681{ 682 char **pbuf = (char **)priv; 683 memcpy(*pbuf, buf, n); 684 *pbuf += n; 685 return NT_STATUS_OK; 686} 687 688ssize_t cli_read(struct cli_state *cli, uint16_t fnum, char *buf, 689 off_t offset, size_t size) 690{ 691 NTSTATUS status; 692 SMB_OFF_T ret; 693 694 status = cli_pull(cli, fnum, offset, size, size, 695 cli_read_sink, &buf, &ret); 696 if (!NT_STATUS_IS_OK(status)) { 697 cli_set_error(cli, status); 698 return -1; 699 } 700 return ret; 701} 702 703/**************************************************************************** 704 Issue a single SMBwrite and don't wait for a reply. 705****************************************************************************/ 706 707static bool cli_issue_write(struct cli_state *cli, 708 uint16_t fnum, 709 off_t offset, 710 uint16 mode, 711 const char *buf, 712 size_t size) 713{ 714 char *p; 715 bool large_writex = false; 716 /* We can only do direct writes if not signing and not encrypting. */ 717 bool direct_writes = !client_is_signing_on(cli) && !cli_encryption_on(cli); 718 719 if (!direct_writes && size + 1 > cli->bufsize) { 720 cli->outbuf = (char *)SMB_REALLOC(cli->outbuf, size + 1024); 721 if (!cli->outbuf) { 722 return False; 723 } 724 cli->inbuf = (char *)SMB_REALLOC(cli->inbuf, size + 1024); 725 if (cli->inbuf == NULL) { 726 SAFE_FREE(cli->outbuf); 727 return False; 728 } 729 cli->bufsize = size + 1024; 730 } 731 732 memset(cli->outbuf,'\0',smb_size); 733 memset(cli->inbuf,'\0',smb_size); 734 735 if (cli->capabilities & CAP_LARGE_FILES) { 736 large_writex = True; 737 } 738 739 if (large_writex) { 740 cli_set_message(cli->outbuf,14,0,True); 741 } else { 742 cli_set_message(cli->outbuf,12,0,True); 743 } 744 745 SCVAL(cli->outbuf,smb_com,SMBwriteX); 746 SSVAL(cli->outbuf,smb_tid,cli->cnum); 747 cli_setup_packet(cli); 748 749 SCVAL(cli->outbuf,smb_vwv0,0xFF); 750 SSVAL(cli->outbuf,smb_vwv2,fnum); 751 752 SIVAL(cli->outbuf,smb_vwv3,offset); 753 SIVAL(cli->outbuf,smb_vwv5,0); 754 SSVAL(cli->outbuf,smb_vwv7,mode); 755 756 SSVAL(cli->outbuf,smb_vwv8,(mode & 0x0008) ? size : 0); 757 /* 758 * According to CIFS-TR-1p00, this following field should only 759 * be set if CAP_LARGE_WRITEX is set. We should check this 760 * locally. However, this check might already have been 761 * done by our callers. 762 */ 763 SSVAL(cli->outbuf,smb_vwv9,(size>>16)); 764 SSVAL(cli->outbuf,smb_vwv10,size); 765 /* +1 is pad byte. */ 766 SSVAL(cli->outbuf,smb_vwv11, 767 smb_buf(cli->outbuf) - smb_base(cli->outbuf) + 1); 768 769 if (large_writex) { 770 SIVAL(cli->outbuf,smb_vwv12,(((uint64_t)offset)>>32) & 0xffffffff); 771 } 772 773 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11) -1; 774 *p++ = '\0'; /* pad byte. */ 775 if (!direct_writes) { 776 memcpy(p, buf, size); 777 } 778 if (size > 0x1FFFF) { 779 /* This is a POSIX 14 word large write. */ 780 set_message_bcc(cli->outbuf, 0); /* Set bcc to zero. */ 781 _smb_setlen_large(cli->outbuf,smb_size + 28 + 1 /* pad */ + size - 4); 782 } else { 783 cli_setup_bcc(cli, p+size); 784 } 785 786 show_msg(cli->outbuf); 787 if (direct_writes) { 788 /* For direct writes we now need to write the data 789 * directly out of buf. */ 790 return cli_send_smb_direct_writeX(cli, buf, size); 791 } else { 792 return cli_send_smb(cli); 793 } 794} 795 796/**************************************************************************** 797 write to a file 798 write_mode: 0x0001 disallow write cacheing 799 0x0002 return bytes remaining 800 0x0004 use raw named pipe protocol 801 0x0008 start of message mode named pipe protocol 802****************************************************************************/ 803 804ssize_t cli_write(struct cli_state *cli, 805 uint16_t fnum, uint16 write_mode, 806 const char *buf, off_t offset, size_t size) 807{ 808 ssize_t bwritten = 0; 809 unsigned int issued = 0; 810 unsigned int received = 0; 811 int mpx = 1; 812 size_t writesize; 813 int blocks; 814 815 if(cli->max_mux > 1) { 816 mpx = cli->max_mux-1; 817 } else { 818 mpx = 1; 819 } 820 821 writesize = cli_write_max_bufsize(cli, write_mode); 822 823 blocks = (size + (writesize-1)) / writesize; 824 825 while (received < blocks) { 826 827 while ((issued - received < mpx) && (issued < blocks)) { 828 ssize_t bsent = issued * writesize; 829 ssize_t size1 = MIN(writesize, size - bsent); 830 831 if (!cli_issue_write(cli, fnum, offset + bsent, 832 write_mode, 833 buf + bsent, 834 size1)) 835 return -1; 836 issued++; 837 } 838 839 if (!cli_receive_smb(cli)) { 840 return bwritten; 841 } 842 843 received++; 844 845 if (cli_is_error(cli)) 846 break; 847 848 bwritten += SVAL(cli->inbuf, smb_vwv2); 849 if (writesize > 0xFFFF) { 850 bwritten += (((int)(SVAL(cli->inbuf, smb_vwv4)))<<16); 851 } 852 } 853 854 while (received < issued && cli_receive_smb(cli)) { 855 received++; 856 } 857 858 return bwritten; 859} 860 861/**************************************************************************** 862 write to a file using a SMBwrite and not bypassing 0 byte writes 863****************************************************************************/ 864 865ssize_t cli_smbwrite(struct cli_state *cli, 866 uint16_t fnum, char *buf, off_t offset, size_t size1) 867{ 868 char *p; 869 ssize_t total = 0; 870 871 do { 872 size_t size = MIN(size1, cli->max_xmit - 48); 873 874 memset(cli->outbuf,'\0',smb_size); 875 memset(cli->inbuf,'\0',smb_size); 876 877 cli_set_message(cli->outbuf,5, 0,True); 878 879 SCVAL(cli->outbuf,smb_com,SMBwrite); 880 SSVAL(cli->outbuf,smb_tid,cli->cnum); 881 cli_setup_packet(cli); 882 883 SSVAL(cli->outbuf,smb_vwv0,fnum); 884 SSVAL(cli->outbuf,smb_vwv1,size); 885 SIVAL(cli->outbuf,smb_vwv2,offset); 886 SSVAL(cli->outbuf,smb_vwv4,0); 887 888 p = smb_buf(cli->outbuf); 889 *p++ = 1; 890 SSVAL(p, 0, size); p += 2; 891 memcpy(p, buf + total, size); p += size; 892 893 cli_setup_bcc(cli, p); 894 895 if (!cli_send_smb(cli)) 896 return -1; 897 898 if (!cli_receive_smb(cli)) 899 return -1; 900 901 if (cli_is_error(cli)) 902 return -1; 903 904 size = SVAL(cli->inbuf,smb_vwv0); 905 if (size == 0) 906 break; 907 908 size1 -= size; 909 total += size; 910 offset += size; 911 912 } while (size1); 913 914 return total; 915} 916 917/* 918 * Send a write&x request 919 */ 920 921struct cli_write_andx_state { 922 size_t size; 923 uint16_t vwv[14]; 924 size_t written; 925 uint8_t pad; 926 struct iovec iov[2]; 927}; 928 929static void cli_write_andx_done(struct tevent_req *subreq); 930 931struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx, 932 struct event_context *ev, 933 struct cli_state *cli, uint16_t fnum, 934 uint16_t mode, const uint8_t *buf, 935 off_t offset, size_t size, 936 struct tevent_req **reqs_before, 937 int num_reqs_before, 938 struct tevent_req **psmbreq) 939{ 940 struct tevent_req *req, *subreq; 941 struct cli_write_andx_state *state; 942 bool bigoffset = ((cli->capabilities & CAP_LARGE_FILES) != 0); 943 uint8_t wct = bigoffset ? 14 : 12; 944 size_t max_write = cli_write_max_bufsize(cli, mode); 945 uint16_t *vwv; 946 947 req = tevent_req_create(mem_ctx, &state, struct cli_write_andx_state); 948 if (req == NULL) { 949 return NULL; 950 } 951 952 size = MIN(size, max_write); 953 954 vwv = state->vwv; 955 956 SCVAL(vwv+0, 0, 0xFF); 957 SCVAL(vwv+0, 1, 0); 958 SSVAL(vwv+1, 0, 0); 959 SSVAL(vwv+2, 0, fnum); 960 SIVAL(vwv+3, 0, offset); 961 SIVAL(vwv+5, 0, 0); 962 SSVAL(vwv+7, 0, mode); 963 SSVAL(vwv+8, 0, 0); 964 SSVAL(vwv+9, 0, (size>>16)); 965 SSVAL(vwv+10, 0, size); 966 967 SSVAL(vwv+11, 0, 968 cli_smb_wct_ofs(reqs_before, num_reqs_before) 969 + 1 /* the wct field */ 970 + wct * 2 /* vwv */ 971 + 2 /* num_bytes field */ 972 + 1 /* pad */); 973 974 if (bigoffset) { 975 SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff); 976 } 977 978 state->pad = 0; 979 state->iov[0].iov_base = (void *)&state->pad; 980 state->iov[0].iov_len = 1; 981 state->iov[1].iov_base = CONST_DISCARD(void *, buf); 982 state->iov[1].iov_len = size; 983 984 subreq = cli_smb_req_create(state, ev, cli, SMBwriteX, 0, wct, vwv, 985 2, state->iov); 986 if (tevent_req_nomem(subreq, req)) { 987 return tevent_req_post(req, ev); 988 } 989 tevent_req_set_callback(subreq, cli_write_andx_done, req); 990 *psmbreq = subreq; 991 return req; 992} 993 994struct tevent_req *cli_write_andx_send(TALLOC_CTX *mem_ctx, 995 struct event_context *ev, 996 struct cli_state *cli, uint16_t fnum, 997 uint16_t mode, const uint8_t *buf, 998 off_t offset, size_t size) 999{ 1000 struct tevent_req *req, *subreq; 1001 NTSTATUS status; 1002 1003 req = cli_write_andx_create(mem_ctx, ev, cli, fnum, mode, buf, offset, 1004 size, NULL, 0, &subreq); 1005 if (req == NULL) { 1006 return NULL; 1007 } 1008 1009 status = cli_smb_req_send(subreq); 1010 if (!NT_STATUS_IS_OK(status)) { 1011 tevent_req_nterror(req, status); 1012 return tevent_req_post(req, ev); 1013 } 1014 return req; 1015} 1016 1017static void cli_write_andx_done(struct tevent_req *subreq) 1018{ 1019 struct tevent_req *req = tevent_req_callback_data( 1020 subreq, struct tevent_req); 1021 struct cli_write_andx_state *state = tevent_req_data( 1022 req, struct cli_write_andx_state); 1023 uint8_t wct; 1024 uint16_t *vwv; 1025 NTSTATUS status; 1026 1027 status = cli_smb_recv(subreq, 6, &wct, &vwv, NULL, NULL); 1028 if (NT_STATUS_IS_ERR(status)) { 1029 TALLOC_FREE(subreq); 1030 tevent_req_nterror(req, status); 1031 return; 1032 } 1033 state->written = SVAL(vwv+2, 0); 1034 state->written |= SVAL(vwv+4, 0)<<16; 1035 tevent_req_done(req); 1036} 1037 1038NTSTATUS cli_write_andx_recv(struct tevent_req *req, size_t *pwritten) 1039{ 1040 struct cli_write_andx_state *state = tevent_req_data( 1041 req, struct cli_write_andx_state); 1042 NTSTATUS status; 1043 1044 if (tevent_req_is_nterror(req, &status)) { 1045 return status; 1046 } 1047 *pwritten = state->written; 1048 return NT_STATUS_OK; 1049} 1050 1051struct cli_writeall_state { 1052 struct event_context *ev; 1053 struct cli_state *cli; 1054 uint16_t fnum; 1055 uint16_t mode; 1056 const uint8_t *buf; 1057 off_t offset; 1058 size_t size; 1059 size_t written; 1060}; 1061 1062static void cli_writeall_written(struct tevent_req *req); 1063 1064static struct tevent_req *cli_writeall_send(TALLOC_CTX *mem_ctx, 1065 struct event_context *ev, 1066 struct cli_state *cli, 1067 uint16_t fnum, 1068 uint16_t mode, 1069 const uint8_t *buf, 1070 off_t offset, size_t size) 1071{ 1072 struct tevent_req *req, *subreq; 1073 struct cli_writeall_state *state; 1074 1075 req = tevent_req_create(mem_ctx, &state, struct cli_writeall_state); 1076 if (req == NULL) { 1077 return NULL; 1078 } 1079 state->ev = ev; 1080 state->cli = cli; 1081 state->fnum = fnum; 1082 state->mode = mode; 1083 state->buf = buf; 1084 state->offset = offset; 1085 state->size = size; 1086 state->written = 0; 1087 1088 subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum, 1089 state->mode, state->buf, state->offset, 1090 state->size); 1091 if (tevent_req_nomem(subreq, req)) { 1092 return tevent_req_post(req, ev); 1093 } 1094 tevent_req_set_callback(subreq, cli_writeall_written, req); 1095 return req; 1096} 1097 1098static void cli_writeall_written(struct tevent_req *subreq) 1099{ 1100 struct tevent_req *req = tevent_req_callback_data( 1101 subreq, struct tevent_req); 1102 struct cli_writeall_state *state = tevent_req_data( 1103 req, struct cli_writeall_state); 1104 NTSTATUS status; 1105 size_t written, to_write; 1106 1107 status = cli_write_andx_recv(subreq, &written); 1108 TALLOC_FREE(subreq); 1109 if (!NT_STATUS_IS_OK(status)) { 1110 tevent_req_nterror(req, status); 1111 return; 1112 } 1113 1114 state->written += written; 1115 1116 if (state->written > state->size) { 1117 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); 1118 return; 1119 } 1120 1121 to_write = state->size - state->written; 1122 1123 if (to_write == 0) { 1124 tevent_req_done(req); 1125 return; 1126 } 1127 1128 subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum, 1129 state->mode, 1130 state->buf + state->written, 1131 state->offset + state->written, to_write); 1132 if (tevent_req_nomem(subreq, req)) { 1133 return; 1134 } 1135 tevent_req_set_callback(subreq, cli_writeall_written, req); 1136} 1137 1138static NTSTATUS cli_writeall_recv(struct tevent_req *req) 1139{ 1140 return tevent_req_simple_recv_ntstatus(req); 1141} 1142 1143struct cli_push_write_state { 1144 struct tevent_req *req;/* This is the main request! Not the subreq */ 1145 uint32_t idx; 1146 off_t ofs; 1147 uint8_t *buf; 1148 size_t size; 1149}; 1150 1151struct cli_push_state { 1152 struct event_context *ev; 1153 struct cli_state *cli; 1154 uint16_t fnum; 1155 uint16_t mode; 1156 off_t start_offset; 1157 size_t window_size; 1158 1159 size_t (*source)(uint8_t *buf, size_t n, void *priv); 1160 void *priv; 1161 1162 bool eof; 1163 1164 size_t chunk_size; 1165 off_t next_offset; 1166 1167 /* 1168 * Outstanding requests 1169 */ 1170 uint32_t pending; 1171 uint32_t num_reqs; 1172 struct cli_push_write_state **reqs; 1173}; 1174 1175static void cli_push_written(struct tevent_req *req); 1176 1177static bool cli_push_write_setup(struct tevent_req *req, 1178 struct cli_push_state *state, 1179 uint32_t idx) 1180{ 1181 struct cli_push_write_state *substate; 1182 struct tevent_req *subreq; 1183 1184 substate = talloc(state->reqs, struct cli_push_write_state); 1185 if (!substate) { 1186 return false; 1187 } 1188 substate->req = req; 1189 substate->idx = idx; 1190 substate->ofs = state->next_offset; 1191 substate->buf = talloc_array(substate, uint8_t, state->chunk_size); 1192 if (!substate->buf) { 1193 talloc_free(substate); 1194 return false; 1195 } 1196 substate->size = state->source(substate->buf, 1197 state->chunk_size, 1198 state->priv); 1199 if (substate->size == 0) { 1200 state->eof = true; 1201 /* nothing to send */ 1202 talloc_free(substate); 1203 return true; 1204 } 1205 1206 subreq = cli_writeall_send(substate, 1207 state->ev, state->cli, 1208 state->fnum, state->mode, 1209 substate->buf, 1210 substate->ofs, 1211 substate->size); 1212 if (!subreq) { 1213 talloc_free(substate); 1214 return false; 1215 } 1216 tevent_req_set_callback(subreq, cli_push_written, substate); 1217 1218 state->reqs[idx] = substate; 1219 state->pending += 1; 1220 state->next_offset += substate->size; 1221 1222 return true; 1223} 1224 1225struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, 1226 struct cli_state *cli, 1227 uint16_t fnum, uint16_t mode, 1228 off_t start_offset, size_t window_size, 1229 size_t (*source)(uint8_t *buf, size_t n, 1230 void *priv), 1231 void *priv) 1232{ 1233 struct tevent_req *req; 1234 struct cli_push_state *state; 1235 uint32_t i; 1236 1237 req = tevent_req_create(mem_ctx, &state, struct cli_push_state); 1238 if (req == NULL) { 1239 return NULL; 1240 } 1241 state->cli = cli; 1242 state->ev = ev; 1243 state->fnum = fnum; 1244 state->start_offset = start_offset; 1245 state->mode = mode; 1246 state->source = source; 1247 state->priv = priv; 1248 state->eof = false; 1249 state->pending = 0; 1250 state->next_offset = start_offset; 1251 1252 state->chunk_size = cli_write_max_bufsize(cli, mode); 1253 1254 if (window_size == 0) { 1255 window_size = cli->max_mux * state->chunk_size; 1256 } 1257 state->num_reqs = window_size/state->chunk_size; 1258 if ((window_size % state->chunk_size) > 0) { 1259 state->num_reqs += 1; 1260 } 1261 state->num_reqs = MIN(state->num_reqs, cli->max_mux); 1262 state->num_reqs = MAX(state->num_reqs, 1); 1263 1264 state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_push_write_state *, 1265 state->num_reqs); 1266 if (state->reqs == NULL) { 1267 goto failed; 1268 } 1269 1270 for (i=0; i<state->num_reqs; i++) { 1271 if (!cli_push_write_setup(req, state, i)) { 1272 goto failed; 1273 } 1274 1275 if (state->eof) { 1276 break; 1277 } 1278 } 1279 1280 if (state->pending == 0) { 1281 tevent_req_done(req); 1282 return tevent_req_post(req, ev); 1283 } 1284 1285 return req; 1286 1287 failed: 1288 tevent_req_nterror(req, NT_STATUS_NO_MEMORY); 1289 return tevent_req_post(req, ev); 1290} 1291 1292static void cli_push_written(struct tevent_req *subreq) 1293{ 1294 struct cli_push_write_state *substate = tevent_req_callback_data( 1295 subreq, struct cli_push_write_state); 1296 struct tevent_req *req = substate->req; 1297 struct cli_push_state *state = tevent_req_data( 1298 req, struct cli_push_state); 1299 NTSTATUS status; 1300 uint32_t idx = substate->idx; 1301 1302 state->reqs[idx] = NULL; 1303 state->pending -= 1; 1304 1305 status = cli_writeall_recv(subreq); 1306 TALLOC_FREE(subreq); 1307 TALLOC_FREE(substate); 1308 if (!NT_STATUS_IS_OK(status)) { 1309 tevent_req_nterror(req, status); 1310 return; 1311 } 1312 1313 if (!state->eof) { 1314 if (!cli_push_write_setup(req, state, idx)) { 1315 tevent_req_nterror(req, NT_STATUS_NO_MEMORY); 1316 return; 1317 } 1318 } 1319 1320 if (state->pending == 0) { 1321 tevent_req_done(req); 1322 return; 1323 } 1324} 1325 1326NTSTATUS cli_push_recv(struct tevent_req *req) 1327{ 1328 return tevent_req_simple_recv_ntstatus(req); 1329} 1330 1331NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, 1332 off_t start_offset, size_t window_size, 1333 size_t (*source)(uint8_t *buf, size_t n, void *priv), 1334 void *priv) 1335{ 1336 TALLOC_CTX *frame = talloc_stackframe(); 1337 struct event_context *ev; 1338 struct tevent_req *req; 1339 NTSTATUS status = NT_STATUS_OK; 1340 1341 if (cli_has_async_calls(cli)) { 1342 /* 1343 * Can't use sync call while an async call is in flight 1344 */ 1345 status = NT_STATUS_INVALID_PARAMETER; 1346 goto fail; 1347 } 1348 1349 ev = event_context_init(frame); 1350 if (ev == NULL) { 1351 status = NT_STATUS_NO_MEMORY; 1352 goto fail; 1353 } 1354 1355 req = cli_push_send(frame, ev, cli, fnum, mode, start_offset, 1356 window_size, source, priv); 1357 if (req == NULL) { 1358 status = NT_STATUS_NO_MEMORY; 1359 goto fail; 1360 } 1361 1362 if (!tevent_req_poll(req, ev)) { 1363 status = map_nt_error_from_unix(errno); 1364 goto fail; 1365 } 1366 1367 status = cli_push_recv(req); 1368 fail: 1369 TALLOC_FREE(frame); 1370 if (!NT_STATUS_IS_OK(status)) { 1371 cli_set_error(cli, status); 1372 } 1373 return status; 1374} 1375