2 Unix SMB/CIFS implementation.
3 client file read/write routines
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
26 /****************************************************************************
27 Calculate the recommended read buffer size
28 ****************************************************************************/
29 static size_t cli_read_max_bufsize(struct cli_state
*cli
)
31 if (!client_is_signing_on(cli
) && !cli_encryption_on(cli
)
32 && (cli
->server_posix_capabilities
& CIFS_UNIX_LARGE_READ_CAP
)) {
33 return CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE
;
35 if (cli
->capabilities
& CAP_LARGE_READX
) {
37 ? CLI_SAMBA_MAX_LARGE_READX_SIZE
38 : CLI_WINDOWS_MAX_LARGE_READX_SIZE
;
40 return (cli
->max_xmit
- (smb_size
+32)) & ~1023;
43 /****************************************************************************
44 Calculate the recommended write buffer size
45 ****************************************************************************/
46 static size_t cli_write_max_bufsize(struct cli_state
*cli
, uint16_t write_mode
)
48 if (write_mode
== 0 &&
49 !client_is_signing_on(cli
) &&
50 !cli_encryption_on(cli
) &&
51 (cli
->server_posix_capabilities
& CIFS_UNIX_LARGE_WRITE_CAP
) &&
52 (cli
->capabilities
& CAP_LARGE_FILES
)) {
53 /* Only do massive writes if we can do them direct
54 * with no signing or encrypting - not on a pipe. */
55 return CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE
;
59 return CLI_SAMBA_MAX_LARGE_WRITEX_SIZE
;
62 if (((cli
->capabilities
& CAP_LARGE_WRITEX
) == 0)
63 || client_is_signing_on(cli
)
64 || strequal(cli
->dev
, "LPT1:")) {
67 * Printer devices are restricted to max_xmit writesize in
68 * Vista and XPSP3 as are signing connections.
71 return (cli
->max_xmit
- (smb_size
+32)) & ~1023;
74 return CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE
;
77 struct cli_read_andx_state
{
85 static void cli_read_andx_done(struct tevent_req
*subreq
);
87 struct tevent_req
*cli_read_andx_create(TALLOC_CTX
*mem_ctx
,
88 struct event_context
*ev
,
89 struct cli_state
*cli
, uint16_t fnum
,
90 off_t offset
, size_t size
,
91 struct tevent_req
**psmbreq
)
93 struct tevent_req
*req
, *subreq
;
94 struct cli_read_andx_state
*state
;
97 if (size
> cli_read_max_bufsize(cli
)) {
98 DEBUG(0, ("cli_read_andx_send got size=%d, can only handle "
99 "size=%d\n", (int)size
,
100 (int)cli_read_max_bufsize(cli
)));
104 req
= tevent_req_create(mem_ctx
, &state
, struct cli_read_andx_state
);
110 SCVAL(state
->vwv
+ 0, 0, 0xFF);
111 SCVAL(state
->vwv
+ 0, 1, 0);
112 SSVAL(state
->vwv
+ 1, 0, 0);
113 SSVAL(state
->vwv
+ 2, 0, fnum
);
114 SIVAL(state
->vwv
+ 3, 0, offset
);
115 SSVAL(state
->vwv
+ 5, 0, size
);
116 SSVAL(state
->vwv
+ 6, 0, size
);
117 SSVAL(state
->vwv
+ 7, 0, (size
>> 16));
118 SSVAL(state
->vwv
+ 8, 0, 0);
119 SSVAL(state
->vwv
+ 9, 0, 0);
121 if ((uint64_t)offset
>> 32) {
122 SIVAL(state
->vwv
+ 10, 0,
123 (((uint64_t)offset
)>>32) & 0xffffffff);
127 subreq
= cli_smb_req_create(state
, ev
, cli
, SMBreadX
, 0, wct
,
128 state
->vwv
, 0, NULL
);
129 if (subreq
== NULL
) {
133 tevent_req_set_callback(subreq
, cli_read_andx_done
, req
);
138 struct tevent_req
*cli_read_andx_send(TALLOC_CTX
*mem_ctx
,
139 struct event_context
*ev
,
140 struct cli_state
*cli
, uint16_t fnum
,
141 off_t offset
, size_t size
)
143 struct tevent_req
*req
, *subreq
;
146 req
= cli_read_andx_create(mem_ctx
, ev
, cli
, fnum
, offset
, size
,
152 status
= cli_smb_req_send(subreq
);
153 if (tevent_req_nterror(req
, status
)) {
154 return tevent_req_post(req
, ev
);
159 static void cli_read_andx_done(struct tevent_req
*subreq
)
161 struct tevent_req
*req
= tevent_req_callback_data(
162 subreq
, struct tevent_req
);
163 struct cli_read_andx_state
*state
= tevent_req_data(
164 req
, struct cli_read_andx_state
);
171 state
->status
= cli_smb_recv(subreq
, state
, &inbuf
, 12, &wct
, &vwv
,
174 if (NT_STATUS_IS_ERR(state
->status
)) {
175 tevent_req_nterror(req
, state
->status
);
179 /* size is the number of bytes the server returned.
181 state
->received
= SVAL(vwv
+ 5, 0);
182 state
->received
|= (((unsigned int)SVAL(vwv
+ 7, 0)) << 16);
184 if (state
->received
> state
->size
) {
185 DEBUG(5,("server returned more than we wanted!\n"));
186 tevent_req_nterror(req
, NT_STATUS_UNEXPECTED_IO_ERROR
);
191 * bcc field must be valid for small reads, for large reads the 16-bit
192 * bcc field can't be correct.
195 if ((state
->received
< 0xffff) && (state
->received
> num_bytes
)) {
196 DEBUG(5, ("server announced more bytes than sent\n"));
197 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
201 state
->buf
= discard_const_p(uint8_t, smb_base(inbuf
)) + SVAL(vwv
+6, 0);
203 if (trans_oob(smb_len(inbuf
), SVAL(vwv
+6, 0), state
->received
)
204 || ((state
->received
!= 0) && (state
->buf
< bytes
))) {
205 DEBUG(5, ("server returned invalid read&x data offset\n"));
206 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
209 tevent_req_done(req
);
213 * Pull the data out of a finished async read_and_x request. rcvbuf is
214 * talloced from the request, so better make sure that you copy it away before
215 * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not
219 NTSTATUS
cli_read_andx_recv(struct tevent_req
*req
, ssize_t
*received
,
222 struct cli_read_andx_state
*state
= tevent_req_data(
223 req
, struct cli_read_andx_state
);
226 if (tevent_req_is_nterror(req
, &status
)) {
229 *received
= state
->received
;
230 *rcvbuf
= state
->buf
;
234 struct cli_readall_state
{
235 struct tevent_context
*ev
;
236 struct cli_state
*cli
;
244 static void cli_readall_done(struct tevent_req
*subreq
);
246 static struct tevent_req
*cli_readall_send(TALLOC_CTX
*mem_ctx
,
247 struct event_context
*ev
,
248 struct cli_state
*cli
,
250 off_t offset
, size_t size
)
252 struct tevent_req
*req
, *subreq
;
253 struct cli_readall_state
*state
;
255 req
= tevent_req_create(mem_ctx
, &state
, struct cli_readall_state
);
262 state
->start_offset
= offset
;
267 subreq
= cli_read_andx_send(state
, ev
, cli
, fnum
, offset
, size
);
268 if (tevent_req_nomem(subreq
, req
)) {
269 return tevent_req_post(req
, ev
);
271 tevent_req_set_callback(subreq
, cli_readall_done
, req
);
275 static void cli_readall_done(struct tevent_req
*subreq
)
277 struct tevent_req
*req
= tevent_req_callback_data(
278 subreq
, struct tevent_req
);
279 struct cli_readall_state
*state
= tevent_req_data(
280 req
, struct cli_readall_state
);
285 status
= cli_read_andx_recv(subreq
, &received
, &buf
);
286 if (tevent_req_nterror(req
, status
)) {
292 tevent_req_done(req
);
296 if ((state
->received
== 0) && (received
== state
->size
)) {
297 /* Ideal case: Got it all in one run */
299 state
->received
+= received
;
300 tevent_req_done(req
);
305 * We got a short read, issue a read for the
306 * rest. Unfortunately we have to allocate the buffer
307 * ourselves now, as our caller expects to receive a single
308 * buffer. cli_read_andx does it from the buffer received from
309 * the net, but with a short read we have to put it together
310 * from several reads.
313 if (state
->buf
== NULL
) {
314 state
->buf
= talloc_array(state
, uint8_t, state
->size
);
315 if (tevent_req_nomem(state
->buf
, req
)) {
319 memcpy(state
->buf
+ state
->received
, buf
, received
);
320 state
->received
+= received
;
324 if (state
->received
>= state
->size
) {
325 tevent_req_done(req
);
329 subreq
= cli_read_andx_send(state
, state
->ev
, state
->cli
, state
->fnum
,
330 state
->start_offset
+ state
->received
,
331 state
->size
- state
->received
);
332 if (tevent_req_nomem(subreq
, req
)) {
335 tevent_req_set_callback(subreq
, cli_readall_done
, req
);
338 static NTSTATUS
cli_readall_recv(struct tevent_req
*req
, ssize_t
*received
,
341 struct cli_readall_state
*state
= tevent_req_data(
342 req
, struct cli_readall_state
);
345 if (tevent_req_is_nterror(req
, &status
)) {
348 *received
= state
->received
;
349 *rcvbuf
= state
->buf
;
353 struct cli_pull_subreq
{
354 struct tevent_req
*req
;
360 * Parallel read support.
362 * cli_pull sends as many read&x requests as the server would allow via
363 * max_mux at a time. When replies flow back in, the data is written into
364 * the callback function "sink" in the right order.
367 struct cli_pull_state
{
368 struct tevent_req
*req
;
370 struct event_context
*ev
;
371 struct cli_state
*cli
;
376 NTSTATUS (*sink
)(char *buf
, size_t n
, void *priv
);
382 * Outstanding requests
385 struct cli_pull_subreq
*reqs
;
388 * For how many bytes did we send requests already?
393 * Next request index to push into "sink". This walks around the "req"
394 * array, taking care that the requests are pushed to "sink" in the
395 * right order. If necessary (i.e. replies don't come in in the right
396 * order), replies are held back in "reqs".
401 * How many bytes did we push into "sink"?
407 static char *cli_pull_print(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
)
409 struct cli_pull_state
*state
= tevent_req_data(
410 req
, struct cli_pull_state
);
413 result
= tevent_req_default_print(req
, mem_ctx
);
414 if (result
== NULL
) {
418 return talloc_asprintf_append_buffer(
419 result
, "num_reqs=%d, top_req=%d",
420 state
->num_reqs
, state
->top_req
);
423 static void cli_pull_read_done(struct tevent_req
*read_req
);
426 * Prepare an async pull request
429 struct tevent_req
*cli_pull_send(TALLOC_CTX
*mem_ctx
,
430 struct event_context
*ev
,
431 struct cli_state
*cli
,
432 uint16_t fnum
, off_t start_offset
,
433 SMB_OFF_T size
, size_t window_size
,
434 NTSTATUS (*sink
)(char *buf
, size_t n
,
438 struct tevent_req
*req
;
439 struct cli_pull_state
*state
;
442 req
= tevent_req_create(mem_ctx
, &state
, struct cli_pull_state
);
446 tevent_req_set_print_fn(req
, cli_pull_print
);
452 state
->start_offset
= start_offset
;
461 tevent_req_done(req
);
462 return tevent_req_post(req
, ev
);
465 state
->chunk_size
= cli_read_max_bufsize(cli
);
467 state
->num_reqs
= MAX(window_size
/state
->chunk_size
, 1);
468 state
->num_reqs
= MIN(state
->num_reqs
, cli
->max_mux
);
470 state
->reqs
= TALLOC_ZERO_ARRAY(state
, struct cli_pull_subreq
,
472 if (state
->reqs
== NULL
) {
476 state
->requested
= 0;
478 for (i
=0; i
<state
->num_reqs
; i
++) {
479 struct cli_pull_subreq
*subreq
= &state
->reqs
[i
];
481 size_t request_thistime
;
483 if (state
->requested
>= size
) {
488 size_left
= size
- state
->requested
;
489 request_thistime
= MIN(size_left
, state
->chunk_size
);
491 subreq
->req
= cli_readall_send(
492 state
->reqs
, ev
, cli
, fnum
,
493 state
->start_offset
+ state
->requested
,
496 if (subreq
->req
== NULL
) {
499 tevent_req_set_callback(subreq
->req
, cli_pull_read_done
, req
);
500 state
->requested
+= request_thistime
;
510 * Handle incoming read replies, push the data into sink and send out new
511 * requests if necessary.
514 static void cli_pull_read_done(struct tevent_req
*subreq
)
516 struct tevent_req
*req
= tevent_req_callback_data(
517 subreq
, struct tevent_req
);
518 struct cli_pull_state
*state
= tevent_req_data(
519 req
, struct cli_pull_state
);
520 struct cli_pull_subreq
*pull_subreq
= NULL
;
524 for (i
= 0; i
< state
->num_reqs
; i
++) {
525 pull_subreq
= &state
->reqs
[i
];
526 if (subreq
== pull_subreq
->req
) {
530 if (i
== state
->num_reqs
) {
531 /* Huh -- received something we did not send?? */
532 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
536 status
= cli_readall_recv(subreq
, &pull_subreq
->received
,
538 if (!NT_STATUS_IS_OK(status
)) {
539 tevent_req_nterror(state
->req
, status
);
544 * This loop is the one to take care of out-of-order replies. All
545 * pending requests are in state->reqs, state->reqs[top_req] is the
546 * one that is to be pushed next. If however a request later than
547 * top_req is replied to, then we can't push yet. If top_req is
548 * replied to at a later point then, we need to push all the finished
552 while (state
->reqs
[state
->top_req
].req
!= NULL
) {
553 struct cli_pull_subreq
*top_subreq
;
555 DEBUG(11, ("cli_pull_read_done: top_req = %d\n",
558 top_subreq
= &state
->reqs
[state
->top_req
];
560 if (tevent_req_is_in_progress(top_subreq
->req
)) {
561 DEBUG(11, ("cli_pull_read_done: top request not yet "
566 DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already "
567 "pushed\n", (int)top_subreq
->received
,
568 (int)state
->pushed
));
570 status
= state
->sink((char *)top_subreq
->buf
,
571 top_subreq
->received
, state
->priv
);
572 if (tevent_req_nterror(state
->req
, status
)) {
575 state
->pushed
+= top_subreq
->received
;
577 TALLOC_FREE(state
->reqs
[state
->top_req
].req
);
579 if (state
->requested
< state
->size
) {
580 struct tevent_req
*new_req
;
582 size_t request_thistime
;
584 size_left
= state
->size
- state
->requested
;
585 request_thistime
= MIN(size_left
, state
->chunk_size
);
587 DEBUG(10, ("cli_pull_read_done: Requesting %d bytes "
588 "at %d, position %d\n",
589 (int)request_thistime
,
590 (int)(state
->start_offset
594 new_req
= cli_readall_send(
595 state
->reqs
, state
->ev
, state
->cli
,
597 state
->start_offset
+ state
->requested
,
600 if (tevent_req_nomem(new_req
, state
->req
)) {
603 tevent_req_set_callback(new_req
, cli_pull_read_done
,
606 state
->reqs
[state
->top_req
].req
= new_req
;
607 state
->requested
+= request_thistime
;
610 state
->top_req
= (state
->top_req
+1) % state
->num_reqs
;
613 tevent_req_done(req
);
616 NTSTATUS
cli_pull_recv(struct tevent_req
*req
, SMB_OFF_T
*received
)
618 struct cli_pull_state
*state
= tevent_req_data(
619 req
, struct cli_pull_state
);
622 if (tevent_req_is_nterror(req
, &status
)) {
625 *received
= state
->pushed
;
629 NTSTATUS
cli_pull(struct cli_state
*cli
, uint16_t fnum
,
630 off_t start_offset
, SMB_OFF_T size
, size_t window_size
,
631 NTSTATUS (*sink
)(char *buf
, size_t n
, void *priv
),
632 void *priv
, SMB_OFF_T
*received
)
634 TALLOC_CTX
*frame
= talloc_stackframe();
635 struct event_context
*ev
;
636 struct tevent_req
*req
;
637 NTSTATUS status
= NT_STATUS_OK
;
639 if (cli_has_async_calls(cli
)) {
641 * Can't use sync call while an async call is in flight
643 status
= NT_STATUS_INVALID_PARAMETER
;
647 ev
= event_context_init(frame
);
649 status
= NT_STATUS_NO_MEMORY
;
653 req
= cli_pull_send(frame
, ev
, cli
, fnum
, start_offset
, size
,
654 window_size
, sink
, priv
);
656 status
= NT_STATUS_NO_MEMORY
;
660 if (!tevent_req_poll(req
, ev
)) {
661 status
= map_nt_error_from_unix(errno
);
665 status
= cli_pull_recv(req
, received
);
668 if (!NT_STATUS_IS_OK(status
)) {
669 cli_set_error(cli
, status
);
674 static NTSTATUS
cli_read_sink(char *buf
, size_t n
, void *priv
)
676 char **pbuf
= (char **)priv
;
677 memcpy(*pbuf
, buf
, n
);
682 ssize_t
cli_read(struct cli_state
*cli
, uint16_t fnum
, char *buf
,
683 off_t offset
, size_t size
)
688 status
= cli_pull(cli
, fnum
, offset
, size
, size
,
689 cli_read_sink
, &buf
, &ret
);
690 if (!NT_STATUS_IS_OK(status
)) {
691 cli_set_error(cli
, status
);
697 /****************************************************************************
698 write to a file using a SMBwrite and not bypassing 0 byte writes
699 ****************************************************************************/
701 NTSTATUS
cli_smbwrite(struct cli_state
*cli
, uint16_t fnum
, char *buf
,
702 off_t offset
, size_t size1
, size_t *ptotal
)
711 bytes
= TALLOC_ARRAY(talloc_tos(), uint8_t, 3);
713 return NT_STATUS_NO_MEMORY
;
718 size_t size
= MIN(size1
, cli
->max_xmit
- 48);
719 struct tevent_req
*req
;
724 SSVAL(vwv
+0, 0, fnum
);
725 SSVAL(vwv
+1, 0, size
);
726 SIVAL(vwv
+2, 0, offset
);
729 bytes
= TALLOC_REALLOC_ARRAY(talloc_tos(), bytes
, uint8_t,
732 return NT_STATUS_NO_MEMORY
;
734 SSVAL(bytes
, 1, size
);
735 memcpy(bytes
+ 3, buf
+ total
, size
);
737 status
= cli_smb(talloc_tos(), cli
, SMBwrite
, 0, 5, vwv
,
738 size
+3, bytes
, &req
, 1, NULL
, &ret_vwv
,
740 if (!NT_STATUS_IS_OK(status
)) {
745 size
= SVAL(ret_vwv
+0, 0);
758 if (ptotal
!= NULL
) {
765 * Send a write&x request
768 struct cli_write_andx_state
{
776 static void cli_write_andx_done(struct tevent_req
*subreq
);
778 struct tevent_req
*cli_write_andx_create(TALLOC_CTX
*mem_ctx
,
779 struct event_context
*ev
,
780 struct cli_state
*cli
, uint16_t fnum
,
781 uint16_t mode
, const uint8_t *buf
,
782 off_t offset
, size_t size
,
783 struct tevent_req
**reqs_before
,
785 struct tevent_req
**psmbreq
)
787 struct tevent_req
*req
, *subreq
;
788 struct cli_write_andx_state
*state
;
789 bool bigoffset
= ((cli
->capabilities
& CAP_LARGE_FILES
) != 0);
790 uint8_t wct
= bigoffset
? 14 : 12;
791 size_t max_write
= cli_write_max_bufsize(cli
, mode
);
794 req
= tevent_req_create(mem_ctx
, &state
, struct cli_write_andx_state
);
799 size
= MIN(size
, max_write
);
803 SCVAL(vwv
+0, 0, 0xFF);
806 SSVAL(vwv
+2, 0, fnum
);
807 SIVAL(vwv
+3, 0, offset
);
809 SSVAL(vwv
+7, 0, mode
);
811 SSVAL(vwv
+9, 0, (size
>>16));
812 SSVAL(vwv
+10, 0, size
);
815 cli_smb_wct_ofs(reqs_before
, num_reqs_before
)
816 + 1 /* the wct field */
818 + 2 /* num_bytes field */
822 SIVAL(vwv
+12, 0, (((uint64_t)offset
)>>32) & 0xffffffff);
826 state
->iov
[0].iov_base
= (void *)&state
->pad
;
827 state
->iov
[0].iov_len
= 1;
828 state
->iov
[1].iov_base
= discard_const_p(void, buf
);
829 state
->iov
[1].iov_len
= size
;
831 subreq
= cli_smb_req_create(state
, ev
, cli
, SMBwriteX
, 0, wct
, vwv
,
833 if (tevent_req_nomem(subreq
, req
)) {
834 return tevent_req_post(req
, ev
);
836 tevent_req_set_callback(subreq
, cli_write_andx_done
, req
);
841 struct tevent_req
*cli_write_andx_send(TALLOC_CTX
*mem_ctx
,
842 struct event_context
*ev
,
843 struct cli_state
*cli
, uint16_t fnum
,
844 uint16_t mode
, const uint8_t *buf
,
845 off_t offset
, size_t size
)
847 struct tevent_req
*req
, *subreq
;
850 req
= cli_write_andx_create(mem_ctx
, ev
, cli
, fnum
, mode
, buf
, offset
,
851 size
, NULL
, 0, &subreq
);
856 status
= cli_smb_req_send(subreq
);
857 if (tevent_req_nterror(req
, status
)) {
858 return tevent_req_post(req
, ev
);
863 static void cli_write_andx_done(struct tevent_req
*subreq
)
865 struct tevent_req
*req
= tevent_req_callback_data(
866 subreq
, struct tevent_req
);
867 struct cli_write_andx_state
*state
= tevent_req_data(
868 req
, struct cli_write_andx_state
);
874 status
= cli_smb_recv(subreq
, state
, &inbuf
, 6, &wct
, &vwv
,
877 if (NT_STATUS_IS_ERR(status
)) {
878 tevent_req_nterror(req
, status
);
881 state
->written
= SVAL(vwv
+2, 0);
882 state
->written
|= SVAL(vwv
+4, 0)<<16;
883 tevent_req_done(req
);
886 NTSTATUS
cli_write_andx_recv(struct tevent_req
*req
, size_t *pwritten
)
888 struct cli_write_andx_state
*state
= tevent_req_data(
889 req
, struct cli_write_andx_state
);
892 if (tevent_req_is_nterror(req
, &status
)) {
895 *pwritten
= state
->written
;
899 struct cli_writeall_state
{
900 struct event_context
*ev
;
901 struct cli_state
*cli
;
910 static void cli_writeall_written(struct tevent_req
*req
);
912 static struct tevent_req
*cli_writeall_send(TALLOC_CTX
*mem_ctx
,
913 struct event_context
*ev
,
914 struct cli_state
*cli
,
918 off_t offset
, size_t size
)
920 struct tevent_req
*req
, *subreq
;
921 struct cli_writeall_state
*state
;
923 req
= tevent_req_create(mem_ctx
, &state
, struct cli_writeall_state
);
932 state
->offset
= offset
;
936 subreq
= cli_write_andx_send(state
, state
->ev
, state
->cli
, state
->fnum
,
937 state
->mode
, state
->buf
, state
->offset
,
939 if (tevent_req_nomem(subreq
, req
)) {
940 return tevent_req_post(req
, ev
);
942 tevent_req_set_callback(subreq
, cli_writeall_written
, req
);
946 static void cli_writeall_written(struct tevent_req
*subreq
)
948 struct tevent_req
*req
= tevent_req_callback_data(
949 subreq
, struct tevent_req
);
950 struct cli_writeall_state
*state
= tevent_req_data(
951 req
, struct cli_writeall_state
);
953 size_t written
, to_write
;
955 status
= cli_write_andx_recv(subreq
, &written
);
957 if (tevent_req_nterror(req
, status
)) {
961 state
->written
+= written
;
963 if (state
->written
> state
->size
) {
964 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
968 to_write
= state
->size
- state
->written
;
971 tevent_req_done(req
);
975 subreq
= cli_write_andx_send(state
, state
->ev
, state
->cli
, state
->fnum
,
977 state
->buf
+ state
->written
,
978 state
->offset
+ state
->written
, to_write
);
979 if (tevent_req_nomem(subreq
, req
)) {
982 tevent_req_set_callback(subreq
, cli_writeall_written
, req
);
985 static NTSTATUS
cli_writeall_recv(struct tevent_req
*req
,
988 struct cli_writeall_state
*state
= tevent_req_data(
989 req
, struct cli_writeall_state
);
992 if (tevent_req_is_nterror(req
, &status
)) {
995 if (pwritten
!= NULL
) {
996 *pwritten
= state
->written
;
1001 NTSTATUS
cli_writeall(struct cli_state
*cli
, uint16_t fnum
, uint16_t mode
,
1002 const uint8_t *buf
, off_t offset
, size_t size
,
1005 TALLOC_CTX
*frame
= talloc_stackframe();
1006 struct event_context
*ev
;
1007 struct tevent_req
*req
;
1008 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1010 if (cli_has_async_calls(cli
)) {
1012 * Can't use sync call while an async call is in flight
1014 status
= NT_STATUS_INVALID_PARAMETER
;
1017 ev
= event_context_init(frame
);
1021 req
= cli_writeall_send(frame
, ev
, cli
, fnum
, mode
, buf
, offset
, size
);
1025 if (!tevent_req_poll(req
, ev
)) {
1026 status
= map_nt_error_from_unix(errno
);
1029 status
= cli_writeall_recv(req
, pwritten
);
1032 if (!NT_STATUS_IS_OK(status
)) {
1033 cli_set_error(cli
, status
);
1038 struct cli_push_write_state
{
1039 struct tevent_req
*req
;/* This is the main request! Not the subreq */
1046 struct cli_push_state
{
1047 struct event_context
*ev
;
1048 struct cli_state
*cli
;
1054 size_t (*source
)(uint8_t *buf
, size_t n
, void *priv
);
1063 * Outstanding requests
1067 struct cli_push_write_state
**reqs
;
1070 static void cli_push_written(struct tevent_req
*req
);
1072 static bool cli_push_write_setup(struct tevent_req
*req
,
1073 struct cli_push_state
*state
,
1076 struct cli_push_write_state
*substate
;
1077 struct tevent_req
*subreq
;
1079 substate
= talloc(state
->reqs
, struct cli_push_write_state
);
1083 substate
->req
= req
;
1084 substate
->idx
= idx
;
1085 substate
->ofs
= state
->next_offset
;
1086 substate
->buf
= talloc_array(substate
, uint8_t, state
->chunk_size
);
1087 if (!substate
->buf
) {
1088 talloc_free(substate
);
1091 substate
->size
= state
->source(substate
->buf
,
1094 if (substate
->size
== 0) {
1096 /* nothing to send */
1097 talloc_free(substate
);
1101 subreq
= cli_writeall_send(substate
,
1102 state
->ev
, state
->cli
,
1103 state
->fnum
, state
->mode
,
1108 talloc_free(substate
);
1111 tevent_req_set_callback(subreq
, cli_push_written
, substate
);
1113 state
->reqs
[idx
] = substate
;
1114 state
->pending
+= 1;
1115 state
->next_offset
+= substate
->size
;
1120 struct tevent_req
*cli_push_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
1121 struct cli_state
*cli
,
1122 uint16_t fnum
, uint16_t mode
,
1123 off_t start_offset
, size_t window_size
,
1124 size_t (*source
)(uint8_t *buf
, size_t n
,
1128 struct tevent_req
*req
;
1129 struct cli_push_state
*state
;
1132 req
= tevent_req_create(mem_ctx
, &state
, struct cli_push_state
);
1139 state
->start_offset
= start_offset
;
1141 state
->source
= source
;
1145 state
->next_offset
= start_offset
;
1147 state
->chunk_size
= cli_write_max_bufsize(cli
, mode
);
1149 if (window_size
== 0) {
1150 window_size
= cli
->max_mux
* state
->chunk_size
;
1152 state
->num_reqs
= window_size
/state
->chunk_size
;
1153 if ((window_size
% state
->chunk_size
) > 0) {
1154 state
->num_reqs
+= 1;
1156 state
->num_reqs
= MIN(state
->num_reqs
, cli
->max_mux
);
1157 state
->num_reqs
= MAX(state
->num_reqs
, 1);
1159 state
->reqs
= TALLOC_ZERO_ARRAY(state
, struct cli_push_write_state
*,
1161 if (state
->reqs
== NULL
) {
1165 for (i
=0; i
<state
->num_reqs
; i
++) {
1166 if (!cli_push_write_setup(req
, state
, i
)) {
1175 if (state
->pending
== 0) {
1176 tevent_req_done(req
);
1177 return tevent_req_post(req
, ev
);
1183 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
1184 return tevent_req_post(req
, ev
);
1187 static void cli_push_written(struct tevent_req
*subreq
)
1189 struct cli_push_write_state
*substate
= tevent_req_callback_data(
1190 subreq
, struct cli_push_write_state
);
1191 struct tevent_req
*req
= substate
->req
;
1192 struct cli_push_state
*state
= tevent_req_data(
1193 req
, struct cli_push_state
);
1195 uint32_t idx
= substate
->idx
;
1197 state
->reqs
[idx
] = NULL
;
1198 state
->pending
-= 1;
1200 status
= cli_writeall_recv(subreq
, NULL
);
1201 TALLOC_FREE(subreq
);
1202 TALLOC_FREE(substate
);
1203 if (tevent_req_nterror(req
, status
)) {
1208 if (!cli_push_write_setup(req
, state
, idx
)) {
1209 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
1214 if (state
->pending
== 0) {
1215 tevent_req_done(req
);
1220 NTSTATUS
cli_push_recv(struct tevent_req
*req
)
1222 return tevent_req_simple_recv_ntstatus(req
);
1225 NTSTATUS
cli_push(struct cli_state
*cli
, uint16_t fnum
, uint16_t mode
,
1226 off_t start_offset
, size_t window_size
,
1227 size_t (*source
)(uint8_t *buf
, size_t n
, void *priv
),
1230 TALLOC_CTX
*frame
= talloc_stackframe();
1231 struct event_context
*ev
;
1232 struct tevent_req
*req
;
1233 NTSTATUS status
= NT_STATUS_OK
;
1235 if (cli_has_async_calls(cli
)) {
1237 * Can't use sync call while an async call is in flight
1239 status
= NT_STATUS_INVALID_PARAMETER
;
1243 ev
= event_context_init(frame
);
1245 status
= NT_STATUS_NO_MEMORY
;
1249 req
= cli_push_send(frame
, ev
, cli
, fnum
, mode
, start_offset
,
1250 window_size
, source
, priv
);
1252 status
= NT_STATUS_NO_MEMORY
;
1256 if (!tevent_req_poll(req
, ev
)) {
1257 status
= map_nt_error_from_unix(errno
);
1261 status
= cli_push_recv(req
);
1264 if (!NT_STATUS_IS_OK(status
)) {
1265 cli_set_error(cli
, status
);