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