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/>.
22
/****************************************************************************
23
Calculate the recommended read buffer size
24
****************************************************************************/
25
static size_t cli_read_max_bufsize(struct cli_state *cli)
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;
31
if (cli->capabilities & CAP_LARGE_READX) {
33
? CLI_SAMBA_MAX_LARGE_READX_SIZE
34
: CLI_WINDOWS_MAX_LARGE_READX_SIZE;
36
return (cli->max_xmit - (smb_size+32)) & ~1023;
39
/****************************************************************************
40
Calculate the recommended write buffer size
41
****************************************************************************/
42
static size_t cli_write_max_bufsize(struct cli_state *cli, uint16_t write_mode)
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;
55
return CLI_SAMBA_MAX_LARGE_WRITEX_SIZE;
58
if (((cli->capabilities & CAP_LARGE_WRITEX) == 0)
59
|| client_is_signing_on(cli)
60
|| strequal(cli->dev, "LPT1:")) {
63
* Printer devices are restricted to max_xmit writesize in
64
* Vista and XPSP3 as are signing connections.
67
return (cli->max_xmit - (smb_size+32)) & ~1023;
70
return CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE;
75
* Send a read&x request
78
struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx,
79
struct event_context *ev,
80
struct cli_state *cli, int fnum,
81
off_t offset, size_t size)
83
struct async_req *result;
84
struct cli_request *req;
85
bool bigoffset = False;
90
if (size > cli_read_max_bufsize(cli)) {
91
DEBUG(0, ("cli_read_andx_send got size=%d, can only handle "
92
"size=%d\n", (int)size,
93
(int)cli_read_max_bufsize(cli)));
97
SCVAL(vwv + 0, 0, 0xFF);
100
SSVAL(vwv + 2, 0, fnum);
101
SIVAL(vwv + 3, 0, offset);
102
SSVAL(vwv + 5, 0, size);
103
SSVAL(vwv + 6, 0, size);
104
SSVAL(vwv + 7, 0, (size >> 16));
105
SSVAL(vwv + 8, 0, 0);
106
SSVAL(vwv + 9, 0, 0);
108
if ((uint64_t)offset >> 32) {
111
(((uint64_t)offset)>>32) & 0xffffffff);
115
result = cli_request_send(mem_ctx, ev, cli, SMBreadX, 0, wct, vwv, 0,
117
if (result == NULL) {
121
req = talloc_get_type_abort(result->private_data, struct cli_request);
123
req->data.read.ofs = offset;
124
req->data.read.size = size;
125
req->data.read.received = 0;
126
req->data.read.rcvbuf = NULL;
132
* Pull the data out of a finished async read_and_x request. rcvbuf is
133
* talloced from the request, so better make sure that you copy it away before
134
* you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not
138
NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received,
141
struct cli_request *cli_req = talloc_get_type_abort(
142
req->private_data, struct cli_request);
151
if (async_req_is_nterror(req, &status)) {
155
status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
157
if (NT_STATUS_IS_ERR(status)) {
162
return NT_STATUS_INVALID_NETWORK_RESPONSE;
165
/* size is the number of bytes the server returned.
167
size = SVAL(vwv + 5, 0);
168
size |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
170
if (size > cli_req->data.read.size) {
171
DEBUG(5,("server returned more than we wanted!\n"));
172
return NT_STATUS_UNEXPECTED_IO_ERROR;
176
* bcc field must be valid for small reads, for large reads the 16-bit
177
* bcc field can't be correct.
180
if ((size < 0xffff) && (size > num_bytes)) {
181
DEBUG(5, ("server announced more bytes than sent\n"));
182
return NT_STATUS_INVALID_NETWORK_RESPONSE;
185
buf = (uint8_t *)smb_base(cli_req->inbuf) + SVAL(vwv+6, 0);
187
if (trans_oob(smb_len(cli_req->inbuf), SVAL(vwv+6, 0), size)
188
|| (size && (buf < bytes))) {
189
DEBUG(5, ("server returned invalid read&x data offset\n"));
190
return NT_STATUS_INVALID_NETWORK_RESPONSE;
193
*rcvbuf = (uint8_t *)(smb_base(cli_req->inbuf) + SVAL(vwv + 6, 0));
198
struct cli_readall_state {
199
struct tevent_context *ev;
200
struct cli_state *cli;
208
static void cli_readall_done(struct async_req *subreq);
210
static struct async_req *cli_readall_send(TALLOC_CTX *mem_ctx,
211
struct event_context *ev,
212
struct cli_state *cli,
214
off_t offset, size_t size)
216
struct async_req *req, *subreq;
217
struct cli_readall_state *state;
219
if (!async_req_setup(mem_ctx, &req, &state,
220
struct cli_readall_state)) {
226
state->start_offset = offset;
231
subreq = cli_read_andx_send(state, ev, cli, fnum, offset, size);
232
if (async_req_nomem(subreq, req)) {
236
subreq->async.fn = cli_readall_done;
237
subreq->async.priv = req;
241
static void cli_readall_done(struct async_req *subreq)
243
struct async_req *req = talloc_get_type_abort(
244
subreq->async.priv, struct async_req);
245
struct cli_readall_state *state = talloc_get_type_abort(
246
req->private_data, struct cli_readall_state);
251
status = cli_read_andx_recv(subreq, &received, &buf);
252
if (!NT_STATUS_IS_OK(status)) {
253
async_req_nterror(req, status);
263
if ((state->received == 0) && (received == state->size)) {
264
/* Ideal case: Got it all in one run */
266
state->received += received;
272
* We got a short read, issue a read for the
273
* rest. Unfortunately we have to allocate the buffer
274
* ourselves now, as our caller expects to receive a single
275
* buffer. cli_read_andx does it from the buffer received from
276
* the net, but with a short read we have to put it together
277
* from several reads.
280
if (state->buf == NULL) {
281
state->buf = talloc_array(state, uint8_t, state->size);
282
if (async_req_nomem(state->buf, req)) {
286
memcpy(state->buf + state->received, buf, received);
287
state->received += received;
291
if (state->received >= state->size) {
296
subreq = cli_read_andx_send(state, state->ev, state->cli, state->fnum,
297
state->start_offset + state->received,
298
state->size - state->received);
299
if (async_req_nomem(subreq, req)) {
302
subreq->async.fn = cli_readall_done;
303
subreq->async.priv = req;
306
static NTSTATUS cli_readall_recv(struct async_req *req, ssize_t *received,
309
struct cli_readall_state *state = talloc_get_type_abort(
310
req->private_data, struct cli_readall_state);
313
if (async_req_is_nterror(req, &status)) {
316
*received = state->received;
317
*rcvbuf = state->buf;
321
struct cli_pull_subreq {
322
struct async_req *req;
328
* Parallel read support.
330
* cli_pull sends as many read&x requests as the server would allow via
331
* max_mux at a time. When replies flow back in, the data is written into
332
* the callback function "sink" in the right order.
335
struct cli_pull_state {
336
struct async_req *req;
338
struct event_context *ev;
339
struct cli_state *cli;
344
NTSTATUS (*sink)(char *buf, size_t n, void *priv);
350
* Outstanding requests
353
struct cli_pull_subreq *reqs;
356
* For how many bytes did we send requests already?
361
* Next request index to push into "sink". This walks around the "req"
362
* array, taking care that the requests are pushed to "sink" in the
363
* right order. If necessary (i.e. replies don't come in in the right
364
* order), replies are held back in "reqs".
369
* How many bytes did we push into "sink"?
375
static char *cli_pull_print(TALLOC_CTX *mem_ctx, struct async_req *req)
377
struct cli_pull_state *state = talloc_get_type_abort(
378
req->private_data, struct cli_pull_state);
381
result = async_req_print(mem_ctx, req);
382
if (result == NULL) {
386
return talloc_asprintf_append_buffer(
387
result, "num_reqs=%d, top_req=%d",
388
state->num_reqs, state->top_req);
391
static void cli_pull_read_done(struct async_req *read_req);
394
* Prepare an async pull request
397
struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx,
398
struct event_context *ev,
399
struct cli_state *cli,
400
uint16_t fnum, off_t start_offset,
401
SMB_OFF_T size, size_t window_size,
402
NTSTATUS (*sink)(char *buf, size_t n,
406
struct async_req *result;
407
struct cli_pull_state *state;
410
if (!async_req_setup(mem_ctx, &result, &state,
411
struct cli_pull_state)) {
414
result->print = cli_pull_print;
420
state->start_offset = start_offset;
429
if (!async_post_ntstatus(result, ev, NT_STATUS_OK)) {
435
state->chunk_size = cli_read_max_bufsize(cli);
437
state->num_reqs = MAX(window_size/state->chunk_size, 1);
438
state->num_reqs = MIN(state->num_reqs, cli->max_mux);
440
state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_pull_subreq,
442
if (state->reqs == NULL) {
446
state->requested = 0;
448
for (i=0; i<state->num_reqs; i++) {
449
struct cli_pull_subreq *subreq = &state->reqs[i];
451
size_t request_thistime;
453
if (state->requested >= size) {
458
size_left = size - state->requested;
459
request_thistime = MIN(size_left, state->chunk_size);
461
subreq->req = cli_readall_send(
462
state->reqs, ev, cli, fnum,
463
state->start_offset + state->requested,
466
if (subreq->req == NULL) {
470
subreq->req->async.fn = cli_pull_read_done;
471
subreq->req->async.priv = result;
473
state->requested += request_thistime;
483
* Handle incoming read replies, push the data into sink and send out new
484
* requests if necessary.
487
static void cli_pull_read_done(struct async_req *read_req)
489
struct async_req *pull_req = talloc_get_type_abort(
490
read_req->async.priv, struct async_req);
491
struct cli_pull_state *state = talloc_get_type_abort(
492
pull_req->private_data, struct cli_pull_state);
493
struct cli_pull_subreq *pull_subreq = NULL;
497
for (i = 0; i < state->num_reqs; i++) {
498
pull_subreq = &state->reqs[i];
499
if (read_req == pull_subreq->req) {
503
if (i == state->num_reqs) {
504
/* Huh -- received something we did not send?? */
505
async_req_nterror(pull_req, NT_STATUS_INTERNAL_ERROR);
509
status = cli_readall_recv(read_req, &pull_subreq->received,
511
if (!NT_STATUS_IS_OK(status)) {
512
async_req_nterror(state->req, status);
517
* This loop is the one to take care of out-of-order replies. All
518
* pending requests are in state->reqs, state->reqs[top_req] is the
519
* one that is to be pushed next. If however a request later than
520
* top_req is replied to, then we can't push yet. If top_req is
521
* replied to at a later point then, we need to push all the finished
525
while (state->reqs[state->top_req].req != NULL) {
526
struct cli_pull_subreq *top_read;
528
DEBUG(11, ("cli_pull_read_done: top_req = %d\n",
531
top_read = &state->reqs[state->top_req];
533
if (state->reqs[state->top_req].req->state < ASYNC_REQ_DONE) {
534
DEBUG(11, ("cli_pull_read_done: top request not yet "
539
DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already "
540
"pushed\n", (int)top_read->received,
541
(int)state->pushed));
543
status = state->sink((char *)top_read->buf,
544
top_read->received, state->priv);
545
if (!NT_STATUS_IS_OK(status)) {
546
async_req_nterror(state->req, status);
549
state->pushed += top_read->received;
551
TALLOC_FREE(state->reqs[state->top_req].req);
553
if (state->requested < state->size) {
554
struct async_req *new_req;
556
size_t request_thistime;
558
size_left = state->size - state->requested;
559
request_thistime = MIN(size_left, state->chunk_size);
561
DEBUG(10, ("cli_pull_read_done: Requesting %d bytes "
562
"at %d, position %d\n",
563
(int)request_thistime,
564
(int)(state->start_offset
568
new_req = cli_readall_send(
569
state->reqs, state->ev, state->cli,
571
state->start_offset + state->requested,
574
if (async_req_nomem(new_req, state->req)) {
578
new_req->async.fn = cli_pull_read_done;
579
new_req->async.priv = pull_req;
581
state->reqs[state->top_req].req = new_req;
582
state->requested += request_thistime;
585
state->top_req = (state->top_req+1) % state->num_reqs;
588
async_req_done(pull_req);
591
NTSTATUS cli_pull_recv(struct async_req *req, SMB_OFF_T *received)
593
struct cli_pull_state *state = talloc_get_type_abort(
594
req->private_data, struct cli_pull_state);
597
if (async_req_is_nterror(req, &status)) {
600
*received = state->pushed;
604
NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
605
off_t start_offset, SMB_OFF_T size, size_t window_size,
606
NTSTATUS (*sink)(char *buf, size_t n, void *priv),
607
void *priv, SMB_OFF_T *received)
609
TALLOC_CTX *frame = talloc_stackframe();
610
struct event_context *ev;
611
struct async_req *req;
612
NTSTATUS result = NT_STATUS_NO_MEMORY;
614
if (cli->fd_event != NULL) {
616
* Can't use sync call while an async call is in flight
618
return NT_STATUS_INVALID_PARAMETER;
621
ev = event_context_init(frame);
626
req = cli_pull_send(frame, ev, cli, fnum, start_offset, size,
627
window_size, sink, priv);
632
while (req->state < ASYNC_REQ_DONE) {
636
result = cli_pull_recv(req, received);
642
static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
644
char **pbuf = (char **)priv;
645
memcpy(*pbuf, buf, n);
650
ssize_t cli_read(struct cli_state *cli, int fnum, char *buf,
651
off_t offset, size_t size)
656
status = cli_pull(cli, fnum, offset, size, size,
657
cli_read_sink, &buf, &ret);
658
if (!NT_STATUS_IS_OK(status)) {
659
cli_set_error(cli, status);
665
/****************************************************************************
666
Issue a single SMBwrite and don't wait for a reply.
667
****************************************************************************/
669
static bool cli_issue_write(struct cli_state *cli,
678
bool large_writex = false;
679
/* We can only do direct writes if not signing and not encrypting. */
680
bool direct_writes = !client_is_signing_on(cli) && !cli_encryption_on(cli);
682
if (!direct_writes && size + 1 > cli->bufsize) {
683
cli->outbuf = (char *)SMB_REALLOC(cli->outbuf, size + 1024);
687
cli->inbuf = (char *)SMB_REALLOC(cli->inbuf, size + 1024);
688
if (cli->inbuf == NULL) {
689
SAFE_FREE(cli->outbuf);
692
cli->bufsize = size + 1024;
695
memset(cli->outbuf,'\0',smb_size);
696
memset(cli->inbuf,'\0',smb_size);
698
if (cli->capabilities & CAP_LARGE_FILES) {
703
cli_set_message(cli->outbuf,14,0,True);
705
cli_set_message(cli->outbuf,12,0,True);
708
SCVAL(cli->outbuf,smb_com,SMBwriteX);
709
SSVAL(cli->outbuf,smb_tid,cli->cnum);
710
cli_setup_packet(cli);
712
SCVAL(cli->outbuf,smb_vwv0,0xFF);
713
SSVAL(cli->outbuf,smb_vwv2,fnum);
715
SIVAL(cli->outbuf,smb_vwv3,offset);
716
SIVAL(cli->outbuf,smb_vwv5,0);
717
SSVAL(cli->outbuf,smb_vwv7,mode);
719
SSVAL(cli->outbuf,smb_vwv8,(mode & 0x0008) ? size : 0);
721
* According to CIFS-TR-1p00, this following field should only
722
* be set if CAP_LARGE_WRITEX is set. We should check this
723
* locally. However, this check might already have been
724
* done by our callers.
726
SSVAL(cli->outbuf,smb_vwv9,(size>>16));
727
SSVAL(cli->outbuf,smb_vwv10,size);
728
/* +1 is pad byte. */
729
SSVAL(cli->outbuf,smb_vwv11,
730
smb_buf(cli->outbuf) - smb_base(cli->outbuf) + 1);
733
SIVAL(cli->outbuf,smb_vwv12,(((uint64_t)offset)>>32) & 0xffffffff);
736
p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11) -1;
737
*p++ = '\0'; /* pad byte. */
738
if (!direct_writes) {
739
memcpy(p, buf, size);
741
if (size > 0x1FFFF) {
742
/* This is a POSIX 14 word large write. */
743
set_message_bcc(cli->outbuf, 0); /* Set bcc to zero. */
744
_smb_setlen_large(cli->outbuf,smb_size + 28 + 1 /* pad */ + size - 4);
746
cli_setup_bcc(cli, p+size);
749
SSVAL(cli->outbuf,smb_mid,cli->mid + i);
751
show_msg(cli->outbuf);
753
/* For direct writes we now need to write the data
754
* directly out of buf. */
755
return cli_send_smb_direct_writeX(cli, buf, size);
757
return cli_send_smb(cli);
761
/****************************************************************************
763
write_mode: 0x0001 disallow write cacheing
764
0x0002 return bytes remaining
765
0x0004 use raw named pipe protocol
766
0x0008 start of message mode named pipe protocol
767
****************************************************************************/
769
ssize_t cli_write(struct cli_state *cli,
770
int fnum, uint16 write_mode,
771
const char *buf, off_t offset, size_t size)
773
ssize_t bwritten = 0;
774
unsigned int issued = 0;
775
unsigned int received = 0;
780
if(cli->max_mux > 1) {
781
mpx = cli->max_mux-1;
786
writesize = cli_write_max_bufsize(cli, write_mode);
788
blocks = (size + (writesize-1)) / writesize;
790
while (received < blocks) {
792
while ((issued - received < mpx) && (issued < blocks)) {
793
ssize_t bsent = issued * writesize;
794
ssize_t size1 = MIN(writesize, size - bsent);
796
if (!cli_issue_write(cli, fnum, offset + bsent,
804
if (!cli_receive_smb(cli)) {
810
if (cli_is_error(cli))
813
bwritten += SVAL(cli->inbuf, smb_vwv2);
814
if (writesize > 0xFFFF) {
815
bwritten += (((int)(SVAL(cli->inbuf, smb_vwv4)))<<16);
819
while (received < issued && cli_receive_smb(cli)) {
826
/****************************************************************************
827
write to a file using a SMBwrite and not bypassing 0 byte writes
828
****************************************************************************/
830
ssize_t cli_smbwrite(struct cli_state *cli,
831
int fnum, char *buf, off_t offset, size_t size1)
837
size_t size = MIN(size1, cli->max_xmit - 48);
839
memset(cli->outbuf,'\0',smb_size);
840
memset(cli->inbuf,'\0',smb_size);
842
cli_set_message(cli->outbuf,5, 0,True);
844
SCVAL(cli->outbuf,smb_com,SMBwrite);
845
SSVAL(cli->outbuf,smb_tid,cli->cnum);
846
cli_setup_packet(cli);
848
SSVAL(cli->outbuf,smb_vwv0,fnum);
849
SSVAL(cli->outbuf,smb_vwv1,size);
850
SIVAL(cli->outbuf,smb_vwv2,offset);
851
SSVAL(cli->outbuf,smb_vwv4,0);
853
p = smb_buf(cli->outbuf);
855
SSVAL(p, 0, size); p += 2;
856
memcpy(p, buf + total, size); p += size;
858
cli_setup_bcc(cli, p);
860
if (!cli_send_smb(cli))
863
if (!cli_receive_smb(cli))
866
if (cli_is_error(cli))
869
size = SVAL(cli->inbuf,smb_vwv0);
883
* Send a write&x request
886
struct async_req *cli_write_andx_send(TALLOC_CTX *mem_ctx,
887
struct event_context *ev,
888
struct cli_state *cli, uint16_t fnum,
889
uint16_t mode, const uint8_t *buf,
890
off_t offset, size_t size)
892
bool bigoffset = ((cli->capabilities & CAP_LARGE_FILES) != 0);
893
uint8_t wct = bigoffset ? 14 : 12;
894
size_t max_write = cli_write_max_bufsize(cli, mode);
897
size = MIN(size, max_write);
899
SCVAL(vwv+0, 0, 0xFF);
902
SSVAL(vwv+2, 0, fnum);
903
SIVAL(vwv+3, 0, offset);
905
SSVAL(vwv+7, 0, mode);
907
SSVAL(vwv+9, 0, (size>>16));
908
SSVAL(vwv+10, 0, size);
912
+ 1 /* the wct field */
914
+ 2 /* num_bytes field */
918
SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
921
return cli_request_send(mem_ctx, ev, cli, SMBwriteX, 0, wct, vwv,
925
NTSTATUS cli_write_andx_recv(struct async_req *req, size_t *pwritten)
934
if (async_req_is_nterror(req, &status)) {
938
status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
940
if (NT_STATUS_IS_ERR(status)) {
945
return NT_STATUS_INVALID_NETWORK_RESPONSE;
948
written = SVAL(vwv+2, 0);
949
written |= SVAL(vwv+4, 0)<<16;
955
struct cli_writeall_state {
956
struct event_context *ev;
957
struct cli_state *cli;
966
static void cli_writeall_written(struct async_req *req);
968
static struct async_req *cli_writeall_send(TALLOC_CTX *mem_ctx,
969
struct event_context *ev,
970
struct cli_state *cli,
974
off_t offset, size_t size)
976
struct async_req *result;
977
struct async_req *subreq;
978
struct cli_writeall_state *state;
980
if (!async_req_setup(mem_ctx, &result, &state,
981
struct cli_writeall_state)) {
989
state->offset = offset;
993
subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
994
state->mode, state->buf, state->offset,
996
if (subreq == NULL) {
1000
subreq->async.fn = cli_writeall_written;
1001
subreq->async.priv = result;
1005
TALLOC_FREE(result);
1009
static void cli_writeall_written(struct async_req *subreq)
1011
struct async_req *req = talloc_get_type_abort(
1012
subreq->async.priv, struct async_req);
1013
struct cli_writeall_state *state = talloc_get_type_abort(
1014
req->private_data, struct cli_writeall_state);
1016
size_t written, to_write;
1018
status = cli_write_andx_recv(subreq, &written);
1019
TALLOC_FREE(subreq);
1020
if (!NT_STATUS_IS_OK(status)) {
1021
async_req_nterror(req, status);
1025
state->written += written;
1027
if (state->written > state->size) {
1028
async_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1032
to_write = state->size - state->written;
1034
if (to_write == 0) {
1035
async_req_done(req);
1039
subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1041
state->buf + state->written,
1042
state->offset + state->written, to_write);
1043
if (subreq == NULL) {
1044
async_req_nterror(req, NT_STATUS_NO_MEMORY);
1048
subreq->async.fn = cli_writeall_written;
1049
subreq->async.priv = req;
1052
static NTSTATUS cli_writeall_recv(struct async_req *req)
1054
return async_req_simple_recv_ntstatus(req);
1057
struct cli_push_write_state {
1058
struct async_req *req;/* This is the main request! Not the subreq */
1065
struct cli_push_state {
1066
struct event_context *ev;
1067
struct cli_state *cli;
1073
size_t (*source)(uint8_t *buf, size_t n, void *priv);
1082
* Outstanding requests
1086
struct cli_push_write_state **reqs;
1089
static void cli_push_written(struct async_req *req);
1091
static bool cli_push_write_setup(struct async_req *req,
1092
struct cli_push_state *state,
1095
struct cli_push_write_state *substate;
1096
struct async_req *subreq;
1098
substate = talloc(state->reqs, struct cli_push_write_state);
1102
substate->req = req;
1103
substate->idx = idx;
1104
substate->ofs = state->next_offset;
1105
substate->buf = talloc_array(substate, uint8_t, state->chunk_size);
1106
if (!substate->buf) {
1107
talloc_free(substate);
1110
substate->size = state->source(substate->buf,
1113
if (substate->size == 0) {
1115
/* nothing to send */
1116
talloc_free(substate);
1120
subreq = cli_writeall_send(substate,
1121
state->ev, state->cli,
1122
state->fnum, state->mode,
1127
talloc_free(substate);
1130
subreq->async.fn = cli_push_written;
1131
subreq->async.priv = substate;
1133
state->reqs[idx] = substate;
1134
state->pending += 1;
1135
state->next_offset += substate->size;
1140
struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
1141
struct cli_state *cli,
1142
uint16_t fnum, uint16_t mode,
1143
off_t start_offset, size_t window_size,
1144
size_t (*source)(uint8_t *buf, size_t n,
1148
struct async_req *req;
1149
struct cli_push_state *state;
1152
if (!async_req_setup(mem_ctx, &req, &state,
1153
struct cli_push_state)) {
1159
state->start_offset = start_offset;
1161
state->source = source;
1165
state->next_offset = start_offset;
1167
state->chunk_size = cli_write_max_bufsize(cli, mode);
1169
if (window_size == 0) {
1170
window_size = cli->max_mux * state->chunk_size;
1172
state->num_reqs = window_size/state->chunk_size;
1173
if ((window_size % state->chunk_size) > 0) {
1174
state->num_reqs += 1;
1176
state->num_reqs = MIN(state->num_reqs, cli->max_mux);
1177
state->num_reqs = MAX(state->num_reqs, 1);
1179
state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_push_write_state *,
1181
if (state->reqs == NULL) {
1185
for (i=0; i<state->num_reqs; i++) {
1186
if (!cli_push_write_setup(req, state, i)) {
1195
if (state->pending == 0) {
1196
if (!async_post_ntstatus(req, ev, NT_STATUS_OK)) {
1209
static void cli_push_written(struct async_req *subreq)
1211
struct cli_push_write_state *substate = talloc_get_type_abort(
1212
subreq->async.priv, struct cli_push_write_state);
1213
struct async_req *req = substate->req;
1214
struct cli_push_state *state = talloc_get_type_abort(
1215
req->private_data, struct cli_push_state);
1217
uint32_t idx = substate->idx;
1219
state->reqs[idx] = NULL;
1220
state->pending -= 1;
1222
status = cli_writeall_recv(subreq);
1223
TALLOC_FREE(subreq);
1224
TALLOC_FREE(substate);
1225
if (!NT_STATUS_IS_OK(status)) {
1226
async_req_nterror(req, status);
1231
if (!cli_push_write_setup(req, state, idx)) {
1232
async_req_nomem(NULL, req);
1237
if (state->pending == 0) {
1238
async_req_done(req);
1243
NTSTATUS cli_push_recv(struct async_req *req)
1245
return async_req_simple_recv_ntstatus(req);
1248
NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1249
off_t start_offset, size_t window_size,
1250
size_t (*source)(uint8_t *buf, size_t n, void *priv),
1253
TALLOC_CTX *frame = talloc_stackframe();
1254
struct event_context *ev;
1255
struct async_req *req;
1256
NTSTATUS result = NT_STATUS_NO_MEMORY;
1258
if (cli->fd_event != NULL) {
1260
* Can't use sync call while an async call is in flight
1262
return NT_STATUS_INVALID_PARAMETER;
1265
ev = event_context_init(frame);
1270
req = cli_push_send(frame, ev, cli, fnum, mode, start_offset,
1271
window_size, source, priv);
1276
while (req->state < ASYNC_REQ_DONE) {
1277
event_loop_once(ev);
1280
result = cli_push_recv(req);