s3:libsmb: rewrite cli_pull* to use smb1cli_conn_req_possible()
[amitay/samba.git] / source3 / libsmb / clireadwrite.c
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 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24 #include "trans2.h"
25 #include "../libcli/smb/smbXcli_base.h"
26
27 /****************************************************************************
28   Calculate the recommended read buffer size
29 ****************************************************************************/
30 static size_t cli_read_max_bufsize(struct cli_state *cli)
31 {
32         uint8_t wct = 12;
33         uint32_t min_space;
34         uint32_t data_offset;
35         uint32_t useable_space = 0;
36
37         data_offset = HDR_VWV;
38         data_offset += wct * sizeof(uint16_t);
39         data_offset += sizeof(uint16_t); /* byte count */
40         data_offset += 1; /* pad */
41
42         min_space = cli_state_available_size(cli, data_offset);
43
44         if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_READ_CAP) {
45                 useable_space = 0xFFFFFF - data_offset;
46
47                 if (smb1cli_conn_signing_is_active(cli->conn)) {
48                         return min_space;
49                 }
50
51                 if (smb1cli_conn_encryption_on(cli->conn)) {
52                         return min_space;
53                 }
54
55                 return useable_space;
56         } else if (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_READX) {
57                 /*
58                  * Note: CAP_LARGE_READX also works with signing
59                  */
60                 useable_space = 0x1FFFF - data_offset;
61
62                 useable_space = MIN(useable_space, UINT16_MAX);
63
64                 return useable_space;
65         }
66
67         return min_space;
68 }
69
70 /****************************************************************************
71   Calculate the recommended write buffer size
72 ****************************************************************************/
73 static size_t cli_write_max_bufsize(struct cli_state *cli,
74                                     uint16_t write_mode,
75                                     uint8_t wct)
76 {
77         uint32_t min_space;
78         uint32_t data_offset;
79         uint32_t useable_space = 0;
80
81         data_offset = HDR_VWV;
82         data_offset += wct * sizeof(uint16_t);
83         data_offset += sizeof(uint16_t); /* byte count */
84         data_offset += 1; /* pad */
85
86         min_space = cli_state_available_size(cli, data_offset);
87
88         if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) {
89                 useable_space = 0xFFFFFF - data_offset;
90         } else if (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_WRITEX) {
91                 useable_space = 0x1FFFF - data_offset;
92         } else {
93                 return min_space;
94         }
95
96         if (write_mode != 0) {
97                 return min_space;
98         }
99
100         if (smb1cli_conn_signing_is_active(cli->conn)) {
101                 return min_space;
102         }
103
104         if (smb1cli_conn_encryption_on(cli->conn)) {
105                 return min_space;
106         }
107
108         if (strequal(cli->dev, "LPT1:")) {
109                 return min_space;
110         }
111
112         return useable_space;
113 }
114
115 struct cli_read_andx_state {
116         size_t size;
117         uint16_t vwv[12];
118         NTSTATUS status;
119         size_t received;
120         uint8_t *buf;
121 };
122
123 static void cli_read_andx_done(struct tevent_req *subreq);
124
125 struct tevent_req *cli_read_andx_create(TALLOC_CTX *mem_ctx,
126                                         struct tevent_context *ev,
127                                         struct cli_state *cli, uint16_t fnum,
128                                         off_t offset, size_t size,
129                                         struct tevent_req **psmbreq)
130 {
131         struct tevent_req *req, *subreq;
132         struct cli_read_andx_state *state;
133         uint8_t wct = 10;
134
135         req = tevent_req_create(mem_ctx, &state, struct cli_read_andx_state);
136         if (req == NULL) {
137                 return NULL;
138         }
139         state->size = size;
140
141         SCVAL(state->vwv + 0, 0, 0xFF);
142         SCVAL(state->vwv + 0, 1, 0);
143         SSVAL(state->vwv + 1, 0, 0);
144         SSVAL(state->vwv + 2, 0, fnum);
145         SIVAL(state->vwv + 3, 0, offset);
146         SSVAL(state->vwv + 5, 0, size);
147         SSVAL(state->vwv + 6, 0, size);
148         SSVAL(state->vwv + 7, 0, (size >> 16));
149         SSVAL(state->vwv + 8, 0, 0);
150         SSVAL(state->vwv + 9, 0, 0);
151
152         if (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES) {
153                 SIVAL(state->vwv + 10, 0,
154                       (((uint64_t)offset)>>32) & 0xffffffff);
155                 wct = 12;
156         } else {
157                 if ((((uint64_t)offset) & 0xffffffff00000000LL) != 0) {
158                         DEBUG(10, ("cli_read_andx_send got large offset where "
159                                    "the server does not support it\n"));
160                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
161                         return tevent_req_post(req, ev);
162                 }
163         }
164
165         subreq = cli_smb_req_create(state, ev, cli, SMBreadX, 0, wct,
166                                     state->vwv, 0, NULL);
167         if (subreq == NULL) {
168                 TALLOC_FREE(req);
169                 return NULL;
170         }
171         tevent_req_set_callback(subreq, cli_read_andx_done, req);
172         *psmbreq = subreq;
173         return req;
174 }
175
176 struct tevent_req *cli_read_andx_send(TALLOC_CTX *mem_ctx,
177                                       struct tevent_context *ev,
178                                       struct cli_state *cli, uint16_t fnum,
179                                       off_t offset, size_t size)
180 {
181         struct tevent_req *req, *subreq;
182         NTSTATUS status;
183
184         req = cli_read_andx_create(mem_ctx, ev, cli, fnum, offset, size,
185                                    &subreq);
186         if (req == NULL) {
187                 return NULL;
188         }
189
190         status = smb1cli_req_chain_submit(&subreq, 1);
191         if (tevent_req_nterror(req, status)) {
192                 return tevent_req_post(req, ev);
193         }
194         return req;
195 }
196
197 static void cli_read_andx_done(struct tevent_req *subreq)
198 {
199         struct tevent_req *req = tevent_req_callback_data(
200                 subreq, struct tevent_req);
201         struct cli_read_andx_state *state = tevent_req_data(
202                 req, struct cli_read_andx_state);
203         uint8_t *inbuf;
204         uint8_t wct;
205         uint16_t *vwv;
206         uint32_t num_bytes;
207         uint8_t *bytes;
208
209         state->status = cli_smb_recv(subreq, state, &inbuf, 12, &wct, &vwv,
210                                      &num_bytes, &bytes);
211         TALLOC_FREE(subreq);
212         if (NT_STATUS_IS_ERR(state->status)) {
213                 tevent_req_nterror(req, state->status);
214                 return;
215         }
216
217         /* size is the number of bytes the server returned.
218          * Might be zero. */
219         state->received = SVAL(vwv + 5, 0);
220         state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
221
222         if (state->received > state->size) {
223                 DEBUG(5,("server returned more than we wanted!\n"));
224                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
225                 return;
226         }
227
228         /*
229          * bcc field must be valid for small reads, for large reads the 16-bit
230          * bcc field can't be correct.
231          */
232
233         if ((state->received < 0xffff) && (state->received > num_bytes)) {
234                 DEBUG(5, ("server announced more bytes than sent\n"));
235                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
236                 return;
237         }
238
239         state->buf = discard_const_p(uint8_t, smb_base(inbuf)) + SVAL(vwv+6, 0);
240
241         if (trans_oob(smb_len_tcp(inbuf), SVAL(vwv+6, 0), state->received)
242             || ((state->received != 0) && (state->buf < bytes))) {
243                 DEBUG(5, ("server returned invalid read&x data offset\n"));
244                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
245                 return;
246         }
247         tevent_req_done(req);
248 }
249
250 /*
251  * Pull the data out of a finished async read_and_x request. rcvbuf is
252  * talloced from the request, so better make sure that you copy it away before
253  * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not
254  * talloc_move it!
255  */
256
257 NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received,
258                             uint8_t **rcvbuf)
259 {
260         struct cli_read_andx_state *state = tevent_req_data(
261                 req, struct cli_read_andx_state);
262         NTSTATUS status;
263
264         if (tevent_req_is_nterror(req, &status)) {
265                 return status;
266         }
267         *received = state->received;
268         *rcvbuf = state->buf;
269         return NT_STATUS_OK;
270 }
271
272 struct cli_readall_state {
273         struct tevent_context *ev;
274         struct cli_state *cli;
275         uint16_t fnum;
276         off_t start_offset;
277         size_t size;
278         size_t received;
279         uint8_t *buf;
280 };
281
282 static void cli_readall_done(struct tevent_req *subreq);
283
284 static struct tevent_req *cli_readall_send(TALLOC_CTX *mem_ctx,
285                                            struct tevent_context *ev,
286                                            struct cli_state *cli,
287                                            uint16_t fnum,
288                                            off_t offset, size_t size)
289 {
290         struct tevent_req *req, *subreq;
291         struct cli_readall_state *state;
292
293         req = tevent_req_create(mem_ctx, &state, struct cli_readall_state);
294         if (req == NULL) {
295                 return NULL;
296         }
297         state->ev = ev;
298         state->cli = cli;
299         state->fnum = fnum;
300         state->start_offset = offset;
301         state->size = size;
302         state->received = 0;
303         state->buf = NULL;
304
305         subreq = cli_read_andx_send(state, ev, cli, fnum, offset, size);
306         if (tevent_req_nomem(subreq, req)) {
307                 return tevent_req_post(req, ev);
308         }
309         tevent_req_set_callback(subreq, cli_readall_done, req);
310         return req;
311 }
312
313 static void cli_readall_done(struct tevent_req *subreq)
314 {
315         struct tevent_req *req = tevent_req_callback_data(
316                 subreq, struct tevent_req);
317         struct cli_readall_state *state = tevent_req_data(
318                 req, struct cli_readall_state);
319         ssize_t received;
320         uint8_t *buf;
321         NTSTATUS status;
322
323         status = cli_read_andx_recv(subreq, &received, &buf);
324         if (tevent_req_nterror(req, status)) {
325                 return;
326         }
327
328         if (received == 0) {
329                 /* EOF */
330                 tevent_req_done(req);
331                 return;
332         }
333
334         if ((state->received == 0) && (received == state->size)) {
335                 /* Ideal case: Got it all in one run */
336                 state->buf = buf;
337                 state->received += received;
338                 tevent_req_done(req);
339                 return;
340         }
341
342         /*
343          * We got a short read, issue a read for the
344          * rest. Unfortunately we have to allocate the buffer
345          * ourselves now, as our caller expects to receive a single
346          * buffer. cli_read_andx does it from the buffer received from
347          * the net, but with a short read we have to put it together
348          * from several reads.
349          */
350
351         if (state->buf == NULL) {
352                 state->buf = talloc_array(state, uint8_t, state->size);
353                 if (tevent_req_nomem(state->buf, req)) {
354                         return;
355                 }
356         }
357         memcpy(state->buf + state->received, buf, received);
358         state->received += received;
359
360         TALLOC_FREE(subreq);
361
362         if (state->received >= state->size) {
363                 tevent_req_done(req);
364                 return;
365         }
366
367         subreq = cli_read_andx_send(state, state->ev, state->cli, state->fnum,
368                                     state->start_offset + state->received,
369                                     state->size - state->received);
370         if (tevent_req_nomem(subreq, req)) {
371                 return;
372         }
373         tevent_req_set_callback(subreq, cli_readall_done, req);
374 }
375
376 static NTSTATUS cli_readall_recv(struct tevent_req *req, ssize_t *received,
377                                  uint8_t **rcvbuf)
378 {
379         struct cli_readall_state *state = tevent_req_data(
380                 req, struct cli_readall_state);
381         NTSTATUS status;
382
383         if (tevent_req_is_nterror(req, &status)) {
384                 return status;
385         }
386         *received = state->received;
387         *rcvbuf = state->buf;
388         return NT_STATUS_OK;
389 }
390
391 struct cli_pull_chunk;
392
393 struct cli_pull_state {
394         struct tevent_context *ev;
395         struct cli_state *cli;
396         uint16_t fnum;
397         off_t start_offset;
398         off_t size;
399
400         NTSTATUS (*sink)(char *buf, size_t n, void *priv);
401         void *priv;
402
403         size_t chunk_size;
404         off_t next_offset;
405         off_t remaining;
406
407         /*
408          * How many bytes did we push into "sink"?
409          */
410         off_t pushed;
411
412         /*
413          * Outstanding requests
414          *
415          * The maximum is 256:
416          * - which would be a window of 256 MByte
417          *   for SMB2 with multi-credit
418          *   or smb1 unix extentions.
419          */
420         uint16_t max_chunks;
421         uint16_t num_chunks;
422         uint16_t num_waiting;
423         struct cli_pull_chunk *chunks;
424 };
425
426 struct cli_pull_chunk {
427         struct cli_pull_chunk *prev, *next;
428         struct tevent_req *req;/* This is the main request! Not the subreq */
429         struct tevent_req *subreq;
430         off_t ofs;
431         uint8_t *buf;
432         size_t total_size;
433         size_t tmp_size;
434         bool done;
435 };
436
437 static void cli_pull_setup_chunks(struct tevent_req *req);
438 static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk);
439 static void cli_pull_chunk_done(struct tevent_req *subreq);
440
441 /*
442  * Parallel read support.
443  *
444  * cli_pull sends as many read&x requests as the server would allow via
445  * max_mux at a time. When replies flow back in, the data is written into
446  * the callback function "sink" in the right order.
447  */
448
449 struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx,
450                                  struct tevent_context *ev,
451                                  struct cli_state *cli,
452                                  uint16_t fnum, off_t start_offset,
453                                  off_t size, size_t window_size,
454                                  NTSTATUS (*sink)(char *buf, size_t n,
455                                                   void *priv),
456                                  void *priv)
457 {
458         struct tevent_req *req;
459         struct cli_pull_state *state;
460         size_t page_size = 1024;
461         uint64_t tmp64;
462
463         req = tevent_req_create(mem_ctx, &state, struct cli_pull_state);
464         if (req == NULL) {
465                 return NULL;
466         }
467         state->cli = cli;
468         state->ev = ev;
469         state->fnum = fnum;
470         state->start_offset = start_offset;
471         state->size = size;
472         state->sink = sink;
473         state->priv = priv;
474         state->next_offset = start_offset;
475         state->remaining = size;
476
477         if (size == 0) {
478                 tevent_req_done(req);
479                 return tevent_req_post(req, ev);
480         }
481
482         state->chunk_size = cli_read_max_bufsize(cli);
483         if (state->chunk_size > page_size) {
484                 state->chunk_size &= ~(page_size - 1);
485         }
486
487         if (window_size == 0) {
488                 /*
489                  * We use 16 MByte as default window size.
490                  */
491                 window_size = 16 * 1024 * 1024;
492         }
493
494         tmp64 = window_size/state->chunk_size;
495         if ((window_size % state->chunk_size) > 0) {
496                 tmp64 += 1;
497         }
498         tmp64 = MAX(tmp64, 1);
499         tmp64 = MIN(tmp64, 256);
500         state->max_chunks = tmp64;
501
502         /*
503          * We defer the callback because of the complex
504          * substate/subfunction logic
505          */
506         tevent_req_defer_callback(req, ev);
507
508         cli_pull_setup_chunks(req);
509         if (!tevent_req_is_in_progress(req)) {
510                 return tevent_req_post(req, ev);
511         }
512
513         return req;
514 }
515
516 static void cli_pull_setup_chunks(struct tevent_req *req)
517 {
518         struct cli_pull_state *state =
519                 tevent_req_data(req,
520                 struct cli_pull_state);
521         struct cli_pull_chunk *chunk, *next = NULL;
522         size_t i;
523
524         for (chunk = state->chunks; chunk; chunk = next) {
525                 /*
526                  * Note that chunk might be removed from this call.
527                  */
528                 next = chunk->next;
529                 cli_pull_chunk_ship(chunk);
530                 if (!tevent_req_is_in_progress(req)) {
531                         return;
532                 }
533         }
534
535         for (i = state->num_chunks; i < state->max_chunks; i++) {
536
537                 if (state->num_waiting > 0) {
538                         return;
539                 }
540
541                 if (state->remaining == 0) {
542                         break;
543                 }
544
545                 chunk = talloc_zero(state, struct cli_pull_chunk);
546                 if (tevent_req_nomem(chunk, req)) {
547                         return;
548                 }
549                 chunk->req = req;
550                 chunk->ofs = state->next_offset;
551                 chunk->total_size = MIN(state->remaining, state->chunk_size);
552                 state->next_offset += chunk->total_size;
553                 state->remaining -= chunk->total_size;
554
555                 DLIST_ADD_END(state->chunks, chunk, NULL);
556                 state->num_chunks++;
557                 state->num_waiting++;
558
559                 cli_pull_chunk_ship(chunk);
560                 if (!tevent_req_is_in_progress(req)) {
561                         return;
562                 }
563         }
564
565         if (state->remaining > 0) {
566                 return;
567         }
568
569         if (state->num_chunks > 0) {
570                 return;
571         }
572
573         tevent_req_done(req);
574 }
575
576 static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk)
577 {
578         struct tevent_req *req = chunk->req;
579         struct cli_pull_state *state =
580                 tevent_req_data(req,
581                 struct cli_pull_state);
582         bool ok;
583         off_t ofs;
584         size_t size;
585
586         if (chunk->done) {
587                 NTSTATUS status;
588
589                 if (chunk != state->chunks) {
590                         /*
591                          * this chunk is not the
592                          * first one in the list.
593                          *
594                          * which means we should not
595                          * push it into the sink yet.
596                          */
597                         return;
598                 }
599
600                 if (chunk->tmp_size == 0) {
601                         /*
602                          * we git a short read, we're done
603                          */
604                         tevent_req_done(req);
605                         return;
606                 }
607
608                 status = state->sink((char *)chunk->buf,
609                                      chunk->tmp_size,
610                                      state->priv);
611                 if (tevent_req_nterror(req, status)) {
612                         return;
613                 }
614                 state->pushed += chunk->tmp_size;
615
616                 if (chunk->tmp_size < chunk->total_size) {
617                         /*
618                          * we git a short read, we're done
619                          */
620                         tevent_req_done(req);
621                         return;
622                 }
623
624                 DLIST_REMOVE(state->chunks, chunk);
625                 SMB_ASSERT(state->num_chunks > 0);
626                 state->num_chunks--;
627                 TALLOC_FREE(chunk);
628
629                 return;
630         }
631
632         if (chunk->subreq != NULL) {
633                 return;
634         }
635
636         SMB_ASSERT(state->num_waiting > 0);
637
638         ofs = chunk->ofs + chunk->tmp_size;
639         size = chunk->total_size - chunk->tmp_size;
640
641         ok = smb1cli_conn_req_possible(state->cli->conn);
642         if (!ok) {
643                 return;
644         }
645
646         chunk->subreq = cli_read_andx_send(chunk,
647                                            state->ev,
648                                            state->cli,
649                                            state->fnum,
650                                            ofs,
651                                            size);
652         if (tevent_req_nomem(chunk->subreq, req)) {
653                 return;
654         }
655         tevent_req_set_callback(chunk->subreq,
656                                 cli_pull_chunk_done,
657                                 chunk);
658
659         state->num_waiting--;
660         return;
661 }
662
663 static void cli_pull_chunk_done(struct tevent_req *subreq)
664 {
665         struct cli_pull_chunk *chunk =
666                 tevent_req_callback_data(subreq,
667                 struct cli_pull_chunk);
668         struct tevent_req *req = chunk->req;
669         struct cli_pull_state *state =
670                 tevent_req_data(req,
671                 struct cli_pull_state);
672         NTSTATUS status;
673         size_t expected = chunk->total_size - chunk->tmp_size;
674         ssize_t received;
675         uint8_t *buf = NULL;
676
677         chunk->subreq = NULL;
678
679         status = cli_read_andx_recv(subreq, &received, &buf);
680         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
681                 received = 0;
682                 status = NT_STATUS_OK;
683         }
684         if (tevent_req_nterror(req, status)) {
685                 return;
686         }
687
688         if (received > expected) {
689                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
690                 return;
691         }
692
693         if (received == 0) {
694                 /*
695                  * We got EOF we're done
696                  */
697                 chunk->done = true;
698                 cli_pull_setup_chunks(req);
699                 return;
700         }
701
702         if (received == chunk->total_size) {
703                 /*
704                  * We got it in the first run.
705                  *
706                  * We don't call TALLOC_FREE(subreq)
707                  * here and keep the returned buffer.
708                  */
709                 chunk->buf = buf;
710         } else if (chunk->buf == NULL) {
711                 chunk->buf = talloc_array(chunk, uint8_t, chunk->total_size);
712                 if (tevent_req_nomem(chunk->buf, req)) {
713                         return;
714                 }
715         }
716
717         if (received != chunk->total_size) {
718                 uint8_t *p = chunk->buf + chunk->tmp_size;
719                 memcpy(p, buf, received);
720                 TALLOC_FREE(subreq);
721         }
722
723         chunk->tmp_size += received;
724
725         if (chunk->tmp_size == chunk->total_size) {
726                 chunk->done = true;
727         } else {
728                 state->num_waiting++;
729         }
730
731         cli_pull_setup_chunks(req);
732 }
733
734 NTSTATUS cli_pull_recv(struct tevent_req *req, off_t *received)
735 {
736         struct cli_pull_state *state = tevent_req_data(
737                 req, struct cli_pull_state);
738         NTSTATUS status;
739
740         if (tevent_req_is_nterror(req, &status)) {
741                 tevent_req_received(req);
742                 return status;
743         }
744         *received = state->pushed;
745         tevent_req_received(req);
746         return NT_STATUS_OK;
747 }
748
749 NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
750                   off_t start_offset, off_t size, size_t window_size,
751                   NTSTATUS (*sink)(char *buf, size_t n, void *priv),
752                   void *priv, off_t *received)
753 {
754         TALLOC_CTX *frame = talloc_stackframe();
755         struct tevent_context *ev;
756         struct tevent_req *req;
757         NTSTATUS status = NT_STATUS_OK;
758
759         if (smbXcli_conn_has_async_calls(cli->conn)) {
760                 /*
761                  * Can't use sync call while an async call is in flight
762                  */
763                 status = NT_STATUS_INVALID_PARAMETER;
764                 goto fail;
765         }
766
767         ev = samba_tevent_context_init(frame);
768         if (ev == NULL) {
769                 status = NT_STATUS_NO_MEMORY;
770                 goto fail;
771         }
772
773         req = cli_pull_send(frame, ev, cli, fnum, start_offset, size,
774                             window_size, sink, priv);
775         if (req == NULL) {
776                 status = NT_STATUS_NO_MEMORY;
777                 goto fail;
778         }
779
780         if (!tevent_req_poll(req, ev)) {
781                 status = map_nt_error_from_unix(errno);
782                 goto fail;
783         }
784
785         status = cli_pull_recv(req, received);
786  fail:
787         TALLOC_FREE(frame);
788         return status;
789 }
790
791 static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
792 {
793         char **pbuf = (char **)priv;
794         memcpy(*pbuf, buf, n);
795         *pbuf += n;
796         return NT_STATUS_OK;
797 }
798
799 NTSTATUS cli_read(struct cli_state *cli, uint16_t fnum,
800                  char *buf, off_t offset, size_t size,
801                  size_t *nread)
802 {
803         NTSTATUS status;
804         off_t ret;
805
806         status = cli_pull(cli, fnum, offset, size, size,
807                           cli_read_sink, &buf, &ret);
808         if (!NT_STATUS_IS_OK(status)) {
809                 return status;
810         }
811
812         if (nread) {
813                 *nread = ret;
814         }
815
816         return NT_STATUS_OK;
817 }
818
819 /****************************************************************************
820   write to a file using a SMBwrite and not bypassing 0 byte writes
821 ****************************************************************************/
822
823 NTSTATUS cli_smbwrite(struct cli_state *cli, uint16_t fnum, char *buf,
824                       off_t offset, size_t size1, size_t *ptotal)
825 {
826         uint8_t *bytes;
827         ssize_t total = 0;
828
829         /*
830          * 3 bytes prefix
831          */
832
833         bytes = talloc_array(talloc_tos(), uint8_t, 3);
834         if (bytes == NULL) {
835                 return NT_STATUS_NO_MEMORY;
836         }
837         bytes[0] = 1;
838
839         do {
840                 uint32_t usable_space = cli_state_available_size(cli, 48);
841                 size_t size = MIN(size1, usable_space);
842                 struct tevent_req *req;
843                 uint16_t vwv[5];
844                 uint16_t *ret_vwv;
845                 NTSTATUS status;
846
847                 SSVAL(vwv+0, 0, fnum);
848                 SSVAL(vwv+1, 0, size);
849                 SIVAL(vwv+2, 0, offset);
850                 SSVAL(vwv+4, 0, 0);
851
852                 bytes = talloc_realloc(talloc_tos(), bytes, uint8_t,
853                                              size+3);
854                 if (bytes == NULL) {
855                         return NT_STATUS_NO_MEMORY;
856                 }
857                 SSVAL(bytes, 1, size);
858                 memcpy(bytes + 3, buf + total, size);
859
860                 status = cli_smb(talloc_tos(), cli, SMBwrite, 0, 5, vwv,
861                                  size+3, bytes, &req, 1, NULL, &ret_vwv,
862                                  NULL, NULL);
863                 if (!NT_STATUS_IS_OK(status)) {
864                         TALLOC_FREE(bytes);
865                         return status;
866                 }
867
868                 size = SVAL(ret_vwv+0, 0);
869                 TALLOC_FREE(req);
870                 if (size == 0) {
871                         break;
872                 }
873                 size1 -= size;
874                 total += size;
875                 offset += size;
876
877         } while (size1);
878
879         TALLOC_FREE(bytes);
880
881         if (ptotal != NULL) {
882                 *ptotal = total;
883         }
884         return NT_STATUS_OK;
885 }
886
887 /*
888  * Send a write&x request
889  */
890
891 struct cli_write_andx_state {
892         size_t size;
893         uint16_t vwv[14];
894         size_t written;
895         uint8_t pad;
896         struct iovec iov[2];
897 };
898
899 static void cli_write_andx_done(struct tevent_req *subreq);
900
901 struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx,
902                                          struct tevent_context *ev,
903                                          struct cli_state *cli, uint16_t fnum,
904                                          uint16_t mode, const uint8_t *buf,
905                                          off_t offset, size_t size,
906                                          struct tevent_req **reqs_before,
907                                          int num_reqs_before,
908                                          struct tevent_req **psmbreq)
909 {
910         struct tevent_req *req, *subreq;
911         struct cli_write_andx_state *state;
912         bool bigoffset = ((smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES) != 0);
913         uint8_t wct = bigoffset ? 14 : 12;
914         size_t max_write = cli_write_max_bufsize(cli, mode, wct);
915         uint16_t *vwv;
916
917         req = tevent_req_create(mem_ctx, &state, struct cli_write_andx_state);
918         if (req == NULL) {
919                 return NULL;
920         }
921
922         state->size = MIN(size, max_write);
923
924         vwv = state->vwv;
925
926         SCVAL(vwv+0, 0, 0xFF);
927         SCVAL(vwv+0, 1, 0);
928         SSVAL(vwv+1, 0, 0);
929         SSVAL(vwv+2, 0, fnum);
930         SIVAL(vwv+3, 0, offset);
931         SIVAL(vwv+5, 0, 0);
932         SSVAL(vwv+7, 0, mode);
933         SSVAL(vwv+8, 0, 0);
934         SSVAL(vwv+9, 0, (state->size>>16));
935         SSVAL(vwv+10, 0, state->size);
936
937         SSVAL(vwv+11, 0,
938               smb1cli_req_wct_ofs(reqs_before, num_reqs_before)
939               + 1               /* the wct field */
940               + wct * 2         /* vwv */
941               + 2               /* num_bytes field */
942               + 1               /* pad */);
943
944         if (bigoffset) {
945                 SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
946         }
947
948         state->pad = 0;
949         state->iov[0].iov_base = (void *)&state->pad;
950         state->iov[0].iov_len = 1;
951         state->iov[1].iov_base = discard_const_p(void, buf);
952         state->iov[1].iov_len = state->size;
953
954         subreq = cli_smb_req_create(state, ev, cli, SMBwriteX, 0, wct, vwv,
955                                     2, state->iov);
956         if (tevent_req_nomem(subreq, req)) {
957                 return tevent_req_post(req, ev);
958         }
959         tevent_req_set_callback(subreq, cli_write_andx_done, req);
960         *psmbreq = subreq;
961         return req;
962 }
963
964 struct tevent_req *cli_write_andx_send(TALLOC_CTX *mem_ctx,
965                                        struct tevent_context *ev,
966                                        struct cli_state *cli, uint16_t fnum,
967                                        uint16_t mode, const uint8_t *buf,
968                                        off_t offset, size_t size)
969 {
970         struct tevent_req *req, *subreq;
971         NTSTATUS status;
972
973         req = cli_write_andx_create(mem_ctx, ev, cli, fnum, mode, buf, offset,
974                                     size, NULL, 0, &subreq);
975         if (req == NULL) {
976                 return NULL;
977         }
978
979         status = smb1cli_req_chain_submit(&subreq, 1);
980         if (tevent_req_nterror(req, status)) {
981                 return tevent_req_post(req, ev);
982         }
983         return req;
984 }
985
986 static void cli_write_andx_done(struct tevent_req *subreq)
987 {
988         struct tevent_req *req = tevent_req_callback_data(
989                 subreq, struct tevent_req);
990         struct cli_write_andx_state *state = tevent_req_data(
991                 req, struct cli_write_andx_state);
992         uint8_t wct;
993         uint16_t *vwv;
994         NTSTATUS status;
995
996         status = cli_smb_recv(subreq, state, NULL, 6, &wct, &vwv,
997                               NULL, NULL);
998         TALLOC_FREE(subreq);
999         if (NT_STATUS_IS_ERR(status)) {
1000                 tevent_req_nterror(req, status);
1001                 return;
1002         }
1003         state->written = SVAL(vwv+2, 0);
1004         if (state->size > UINT16_MAX) {
1005                 /*
1006                  * It is important that we only set the
1007                  * high bits only if we asked for a large write.
1008                  *
1009                  * OS/2 print shares get this wrong and may send
1010                  * invalid values.
1011                  *
1012                  * See bug #5326.
1013                  */
1014                 state->written |= SVAL(vwv+4, 0)<<16;
1015         }
1016         tevent_req_done(req);
1017 }
1018
1019 NTSTATUS cli_write_andx_recv(struct tevent_req *req, size_t *pwritten)
1020 {
1021         struct cli_write_andx_state *state = tevent_req_data(
1022                 req, struct cli_write_andx_state);
1023         NTSTATUS status;
1024
1025         if (tevent_req_is_nterror(req, &status)) {
1026                 return status;
1027         }
1028         if (pwritten != 0) {
1029                 *pwritten = state->written;
1030         }
1031         return NT_STATUS_OK;
1032 }
1033
1034 struct cli_writeall_state {
1035         struct tevent_context *ev;
1036         struct cli_state *cli;
1037         uint16_t fnum;
1038         uint16_t mode;
1039         const uint8_t *buf;
1040         off_t offset;
1041         size_t size;
1042         size_t written;
1043 };
1044
1045 static void cli_writeall_written(struct tevent_req *req);
1046
1047 static struct tevent_req *cli_writeall_send(TALLOC_CTX *mem_ctx,
1048                                             struct tevent_context *ev,
1049                                             struct cli_state *cli,
1050                                             uint16_t fnum,
1051                                             uint16_t mode,
1052                                             const uint8_t *buf,
1053                                             off_t offset, size_t size)
1054 {
1055         struct tevent_req *req, *subreq;
1056         struct cli_writeall_state *state;
1057
1058         req = tevent_req_create(mem_ctx, &state, struct cli_writeall_state);
1059         if (req == NULL) {
1060                 return NULL;
1061         }
1062         state->ev = ev;
1063         state->cli = cli;
1064         state->fnum = fnum;
1065         state->mode = mode;
1066         state->buf = buf;
1067         state->offset = offset;
1068         state->size = size;
1069         state->written = 0;
1070
1071         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1072                                      state->mode, state->buf, state->offset,
1073                                      state->size);
1074         if (tevent_req_nomem(subreq, req)) {
1075                 return tevent_req_post(req, ev);
1076         }
1077         tevent_req_set_callback(subreq, cli_writeall_written, req);
1078         return req;
1079 }
1080
1081 static void cli_writeall_written(struct tevent_req *subreq)
1082 {
1083         struct tevent_req *req = tevent_req_callback_data(
1084                 subreq, struct tevent_req);
1085         struct cli_writeall_state *state = tevent_req_data(
1086                 req, struct cli_writeall_state);
1087         NTSTATUS status;
1088         size_t written, to_write;
1089
1090         status = cli_write_andx_recv(subreq, &written);
1091         TALLOC_FREE(subreq);
1092         if (tevent_req_nterror(req, status)) {
1093                 return;
1094         }
1095
1096         state->written += written;
1097
1098         if (state->written > state->size) {
1099                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1100                 return;
1101         }
1102
1103         to_write = state->size - state->written;
1104
1105         if (to_write == 0) {
1106                 tevent_req_done(req);
1107                 return;
1108         }
1109
1110         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1111                                      state->mode,
1112                                      state->buf + state->written,
1113                                      state->offset + state->written, to_write);
1114         if (tevent_req_nomem(subreq, req)) {
1115                 return;
1116         }
1117         tevent_req_set_callback(subreq, cli_writeall_written, req);
1118 }
1119
1120 static NTSTATUS cli_writeall_recv(struct tevent_req *req,
1121                                   size_t *pwritten)
1122 {
1123         struct cli_writeall_state *state = tevent_req_data(
1124                 req, struct cli_writeall_state);
1125         NTSTATUS status;
1126
1127         if (tevent_req_is_nterror(req, &status)) {
1128                 return status;
1129         }
1130         if (pwritten != NULL) {
1131                 *pwritten = state->written;
1132         }
1133         return NT_STATUS_OK;
1134 }
1135
1136 NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1137                       const uint8_t *buf, off_t offset, size_t size,
1138                       size_t *pwritten)
1139 {
1140         TALLOC_CTX *frame = talloc_stackframe();
1141         struct tevent_context *ev;
1142         struct tevent_req *req;
1143         NTSTATUS status = NT_STATUS_NO_MEMORY;
1144
1145         if (smbXcli_conn_has_async_calls(cli->conn)) {
1146                 /*
1147                  * Can't use sync call while an async call is in flight
1148                  */
1149                 status = NT_STATUS_INVALID_PARAMETER;
1150                 goto fail;
1151         }
1152         ev = samba_tevent_context_init(frame);
1153         if (ev == NULL) {
1154                 goto fail;
1155         }
1156         req = cli_writeall_send(frame, ev, cli, fnum, mode, buf, offset, size);
1157         if (req == NULL) {
1158                 goto fail;
1159         }
1160         if (!tevent_req_poll(req, ev)) {
1161                 status = map_nt_error_from_unix(errno);
1162                 goto fail;
1163         }
1164         status = cli_writeall_recv(req, pwritten);
1165  fail:
1166         TALLOC_FREE(frame);
1167         return status;
1168 }
1169
1170 struct cli_push_chunk;
1171
1172 struct cli_push_state {
1173         struct tevent_context *ev;
1174         struct cli_state *cli;
1175         uint16_t fnum;
1176         uint16_t mode;
1177         off_t start_offset;
1178
1179         size_t (*source)(uint8_t *buf, size_t n, void *priv);
1180         void *priv;
1181
1182         bool eof;
1183
1184         size_t chunk_size;
1185         off_t next_offset;
1186
1187         /*
1188          * Outstanding requests
1189          *
1190          * The maximum is 256:
1191          * - which would be a window of 256 MByte
1192          *   for SMB2 with multi-credit
1193          *   or smb1 unix extentions.
1194          */
1195         uint16_t max_chunks;
1196         uint16_t num_chunks;
1197         uint16_t num_waiting;
1198         struct cli_push_chunk *chunks;
1199 };
1200
1201 struct cli_push_chunk {
1202         struct cli_push_chunk *prev, *next;
1203         struct tevent_req *req;/* This is the main request! Not the subreq */
1204         struct tevent_req *subreq;
1205         off_t ofs;
1206         uint8_t *buf;
1207         size_t total_size;
1208         size_t tmp_size;
1209         bool done;
1210 };
1211
1212 static void cli_push_setup_chunks(struct tevent_req *req);
1213 static void cli_push_chunk_ship(struct cli_push_chunk *chunk);
1214 static void cli_push_chunk_done(struct tevent_req *subreq);
1215
1216 struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1217                                  struct cli_state *cli,
1218                                  uint16_t fnum, uint16_t mode,
1219                                  off_t start_offset, size_t window_size,
1220                                  size_t (*source)(uint8_t *buf, size_t n,
1221                                                   void *priv),
1222                                  void *priv)
1223 {
1224         struct tevent_req *req;
1225         struct cli_push_state *state;
1226         size_t page_size = 1024;
1227         uint64_t tmp64;
1228
1229         req = tevent_req_create(mem_ctx, &state, struct cli_push_state);
1230         if (req == NULL) {
1231                 return NULL;
1232         }
1233         state->cli = cli;
1234         state->ev = ev;
1235         state->fnum = fnum;
1236         state->start_offset = start_offset;
1237         state->mode = mode;
1238         state->source = source;
1239         state->priv = priv;
1240         state->next_offset = start_offset;
1241
1242         state->chunk_size = cli_write_max_bufsize(cli, mode, 14);
1243         if (state->chunk_size > page_size) {
1244                 state->chunk_size &= ~(page_size - 1);
1245         }
1246
1247         if (window_size == 0) {
1248                 /*
1249                  * We use 16 MByte as default window size.
1250                  */
1251                 window_size = 16 * 1024 * 1024;
1252         }
1253
1254         tmp64 = window_size/state->chunk_size;
1255         if ((window_size % state->chunk_size) > 0) {
1256                 tmp64 += 1;
1257         }
1258         tmp64 = MAX(tmp64, 1);
1259         tmp64 = MIN(tmp64, 256);
1260         state->max_chunks = tmp64;
1261
1262         /*
1263          * We defer the callback because of the complex
1264          * substate/subfunction logic
1265          */
1266         tevent_req_defer_callback(req, ev);
1267
1268         cli_push_setup_chunks(req);
1269         if (!tevent_req_is_in_progress(req)) {
1270                 return tevent_req_post(req, ev);
1271         }
1272
1273         return req;
1274 }
1275
1276 static void cli_push_setup_chunks(struct tevent_req *req)
1277 {
1278         struct cli_push_state *state =
1279                 tevent_req_data(req,
1280                 struct cli_push_state);
1281         struct cli_push_chunk *chunk, *next = NULL;
1282         size_t i;
1283
1284         for (chunk = state->chunks; chunk; chunk = next) {
1285                 /*
1286                  * Note that chunk might be removed from this call.
1287                  */
1288                 next = chunk->next;
1289                 cli_push_chunk_ship(chunk);
1290                 if (!tevent_req_is_in_progress(req)) {
1291                         return;
1292                 }
1293         }
1294
1295         for (i = state->num_chunks; i < state->max_chunks; i++) {
1296
1297                 if (state->num_waiting > 0) {
1298                         return;
1299                 }
1300
1301                 if (state->eof) {
1302                         break;
1303                 }
1304
1305                 chunk = talloc_zero(state, struct cli_push_chunk);
1306                 if (tevent_req_nomem(chunk, req)) {
1307                         return;
1308                 }
1309                 chunk->req = req;
1310                 chunk->ofs = state->next_offset;
1311                 chunk->buf = talloc_array(chunk,
1312                                           uint8_t,
1313                                           state->chunk_size);
1314                 if (tevent_req_nomem(chunk->buf, req)) {
1315                         return;
1316                 }
1317                 chunk->total_size = state->source(chunk->buf,
1318                                                   state->chunk_size,
1319                                                   state->priv);
1320                 if (chunk->total_size == 0) {
1321                         /* nothing to send */
1322                         talloc_free(chunk);
1323                         state->eof = true;
1324                         break;
1325                 }
1326                 state->next_offset += chunk->total_size;
1327
1328                 DLIST_ADD_END(state->chunks, chunk, NULL);
1329                 state->num_chunks++;
1330                 state->num_waiting++;
1331
1332                 cli_push_chunk_ship(chunk);
1333                 if (!tevent_req_is_in_progress(req)) {
1334                         return;
1335                 }
1336         }
1337
1338         if (!state->eof) {
1339                 return;
1340         }
1341
1342         if (state->num_chunks > 0) {
1343                 return;
1344         }
1345
1346         tevent_req_done(req);
1347 }
1348
1349 static void cli_push_chunk_ship(struct cli_push_chunk *chunk)
1350 {
1351         struct tevent_req *req = chunk->req;
1352         struct cli_push_state *state =
1353                 tevent_req_data(req,
1354                 struct cli_push_state);
1355         bool ok;
1356         const uint8_t *buf;
1357         off_t ofs;
1358         size_t size;
1359
1360         if (chunk->done) {
1361                 DLIST_REMOVE(state->chunks, chunk);
1362                 SMB_ASSERT(state->num_chunks > 0);
1363                 state->num_chunks--;
1364                 TALLOC_FREE(chunk);
1365
1366                 return;
1367         }
1368
1369         if (chunk->subreq != NULL) {
1370                 return;
1371         }
1372
1373         SMB_ASSERT(state->num_waiting > 0);
1374
1375         buf = chunk->buf + chunk->tmp_size;
1376         ofs = chunk->ofs + chunk->tmp_size;
1377         size = chunk->total_size - chunk->tmp_size;
1378
1379         ok = smb1cli_conn_req_possible(state->cli->conn);
1380         if (!ok) {
1381                 return;
1382         }
1383
1384         chunk->subreq = cli_write_andx_send(chunk,
1385                                             state->ev,
1386                                             state->cli,
1387                                             state->fnum,
1388                                             state->mode,
1389                                             buf,
1390                                             ofs,
1391                                             size);
1392         if (tevent_req_nomem(chunk->subreq, req)) {
1393                 return;
1394         }
1395         tevent_req_set_callback(chunk->subreq,
1396                                 cli_push_chunk_done,
1397                                 chunk);
1398
1399         state->num_waiting--;
1400         return;
1401 }
1402
1403 static void cli_push_chunk_done(struct tevent_req *subreq)
1404 {
1405         struct cli_push_chunk *chunk =
1406                 tevent_req_callback_data(subreq,
1407                 struct cli_push_chunk);
1408         struct tevent_req *req = chunk->req;
1409         struct cli_push_state *state =
1410                 tevent_req_data(req,
1411                 struct cli_push_state);
1412         NTSTATUS status;
1413         size_t expected = chunk->total_size - chunk->tmp_size;
1414         size_t written;
1415
1416         chunk->subreq = NULL;
1417
1418         status = cli_write_andx_recv(subreq, &written);
1419         TALLOC_FREE(subreq);
1420         if (tevent_req_nterror(req, status)) {
1421                 return;
1422         }
1423
1424         if (written > expected) {
1425                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1426                 return;
1427         }
1428
1429         if (written == 0) {
1430                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1431                 return;
1432         }
1433
1434         chunk->tmp_size += written;
1435
1436         if (chunk->tmp_size == chunk->total_size) {
1437                 chunk->done = true;
1438         } else {
1439                 state->num_waiting++;
1440         }
1441
1442         cli_push_setup_chunks(req);
1443 }
1444
1445 NTSTATUS cli_push_recv(struct tevent_req *req)
1446 {
1447         return tevent_req_simple_recv_ntstatus(req);
1448 }
1449
1450 NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1451                   off_t start_offset, size_t window_size,
1452                   size_t (*source)(uint8_t *buf, size_t n, void *priv),
1453                   void *priv)
1454 {
1455         TALLOC_CTX *frame = talloc_stackframe();
1456         struct tevent_context *ev;
1457         struct tevent_req *req;
1458         NTSTATUS status = NT_STATUS_OK;
1459
1460         if (smbXcli_conn_has_async_calls(cli->conn)) {
1461                 /*
1462                  * Can't use sync call while an async call is in flight
1463                  */
1464                 status = NT_STATUS_INVALID_PARAMETER;
1465                 goto fail;
1466         }
1467
1468         ev = samba_tevent_context_init(frame);
1469         if (ev == NULL) {
1470                 status = NT_STATUS_NO_MEMORY;
1471                 goto fail;
1472         }
1473
1474         req = cli_push_send(frame, ev, cli, fnum, mode, start_offset,
1475                             window_size, source, priv);
1476         if (req == NULL) {
1477                 status = NT_STATUS_NO_MEMORY;
1478                 goto fail;
1479         }
1480
1481         if (!tevent_req_poll(req, ev)) {
1482                 status = map_nt_error_from_unix(errno);
1483                 goto fail;
1484         }
1485
1486         status = cli_push_recv(req);
1487  fail:
1488         TALLOC_FREE(frame);
1489         return status;
1490 }