47e7f1bfd4c65880df772d3f68397fab80715733
[obnox/samba/samba-obnox.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_subreq {
392         struct tevent_req *req;
393         ssize_t received;
394         uint8_t *buf;
395 };
396
397 /*
398  * Parallel read support.
399  *
400  * cli_pull sends as many read&x requests as the server would allow via
401  * max_mux at a time. When replies flow back in, the data is written into
402  * the callback function "sink" in the right order.
403  */
404
405 struct cli_pull_state {
406         struct tevent_req *req;
407
408         struct tevent_context *ev;
409         struct cli_state *cli;
410         uint16_t fnum;
411         off_t start_offset;
412         off_t size;
413
414         NTSTATUS (*sink)(char *buf, size_t n, void *priv);
415         void *priv;
416
417         size_t chunk_size;
418
419         /*
420          * Outstanding requests
421          */
422         uint16_t max_reqs;
423         int num_reqs;
424         struct cli_pull_subreq *reqs;
425
426         /*
427          * For how many bytes did we send requests already?
428          */
429         off_t requested;
430
431         /*
432          * Next request index to push into "sink". This walks around the "req"
433          * array, taking care that the requests are pushed to "sink" in the
434          * right order. If necessary (i.e. replies don't come in in the right
435          * order), replies are held back in "reqs".
436          */
437         int top_req;
438
439         /*
440          * How many bytes did we push into "sink"?
441          */
442
443         off_t pushed;
444 };
445
446 static char *cli_pull_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
447 {
448         struct cli_pull_state *state = tevent_req_data(
449                 req, struct cli_pull_state);
450         char *result;
451
452         result = tevent_req_default_print(req, mem_ctx);
453         if (result == NULL) {
454                 return NULL;
455         }
456
457         return talloc_asprintf_append_buffer(
458                 result, "num_reqs=%d, top_req=%d",
459                 state->num_reqs, state->top_req);
460 }
461
462 static void cli_pull_read_done(struct tevent_req *read_req);
463
464 /*
465  * Prepare an async pull request
466  */
467
468 struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx,
469                                  struct tevent_context *ev,
470                                  struct cli_state *cli,
471                                  uint16_t fnum, off_t start_offset,
472                                  off_t size, size_t window_size,
473                                  NTSTATUS (*sink)(char *buf, size_t n,
474                                                   void *priv),
475                                  void *priv)
476 {
477         struct tevent_req *req;
478         struct cli_pull_state *state;
479         int i;
480         size_t page_size = 1024;
481
482         req = tevent_req_create(mem_ctx, &state, struct cli_pull_state);
483         if (req == NULL) {
484                 return NULL;
485         }
486         tevent_req_set_print_fn(req, cli_pull_print);
487         state->req = req;
488
489         state->cli = cli;
490         state->ev = ev;
491         state->fnum = fnum;
492         state->start_offset = start_offset;
493         state->size = size;
494         state->sink = sink;
495         state->priv = priv;
496
497         state->pushed = 0;
498         state->top_req = 0;
499
500         if (size == 0) {
501                 tevent_req_done(req);
502                 return tevent_req_post(req, ev);
503         }
504
505         state->chunk_size = cli_read_max_bufsize(cli);
506         if (state->chunk_size > page_size) {
507                 state->chunk_size &= ~(page_size - 1);
508         }
509
510         state->max_reqs = smbXcli_conn_max_requests(cli->conn);
511
512         state->num_reqs = MAX(window_size/state->chunk_size, 1);
513         state->num_reqs = MIN(state->num_reqs, state->max_reqs);
514
515         state->reqs = talloc_zero_array(state, struct cli_pull_subreq,
516                                         state->num_reqs);
517         if (state->reqs == NULL) {
518                 goto failed;
519         }
520
521         state->requested = 0;
522
523         for (i=0; i<state->num_reqs; i++) {
524                 struct cli_pull_subreq *subreq = &state->reqs[i];
525                 off_t size_left;
526                 size_t request_thistime;
527
528                 if (state->requested >= size) {
529                         state->num_reqs = i;
530                         break;
531                 }
532
533                 size_left = size - state->requested;
534                 request_thistime = MIN(size_left, state->chunk_size);
535
536                 subreq->req = cli_readall_send(
537                         state->reqs, ev, cli, fnum,
538                         state->start_offset + state->requested,
539                         request_thistime);
540
541                 if (subreq->req == NULL) {
542                         goto failed;
543                 }
544                 tevent_req_set_callback(subreq->req, cli_pull_read_done, req);
545                 state->requested += request_thistime;
546         }
547         return req;
548
549 failed:
550         TALLOC_FREE(req);
551         return NULL;
552 }
553
554 /*
555  * Handle incoming read replies, push the data into sink and send out new
556  * requests if necessary.
557  */
558
559 static void cli_pull_read_done(struct tevent_req *subreq)
560 {
561         struct tevent_req *req = tevent_req_callback_data(
562                 subreq, struct tevent_req);
563         struct cli_pull_state *state = tevent_req_data(
564                 req, struct cli_pull_state);
565         struct cli_pull_subreq *pull_subreq = NULL;
566         NTSTATUS status;
567         int i;
568
569         for (i = 0; i < state->num_reqs; i++) {
570                 pull_subreq = &state->reqs[i];
571                 if (subreq == pull_subreq->req) {
572                         break;
573                 }
574         }
575         if (i == state->num_reqs) {
576                 /* Huh -- received something we did not send?? */
577                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
578                 return;
579         }
580
581         status = cli_readall_recv(subreq, &pull_subreq->received,
582                                   &pull_subreq->buf);
583         if (!NT_STATUS_IS_OK(status)) {
584                 tevent_req_nterror(state->req, status);
585                 return;
586         }
587
588         /*
589          * This loop is the one to take care of out-of-order replies. All
590          * pending requests are in state->reqs, state->reqs[top_req] is the
591          * one that is to be pushed next. If however a request later than
592          * top_req is replied to, then we can't push yet. If top_req is
593          * replied to at a later point then, we need to push all the finished
594          * requests.
595          */
596
597         while (state->reqs[state->top_req].req != NULL) {
598                 struct cli_pull_subreq *top_subreq;
599
600                 DEBUG(11, ("cli_pull_read_done: top_req = %d\n",
601                            state->top_req));
602
603                 top_subreq = &state->reqs[state->top_req];
604
605                 if (tevent_req_is_in_progress(top_subreq->req)) {
606                         DEBUG(11, ("cli_pull_read_done: top request not yet "
607                                    "done\n"));
608                         return;
609                 }
610
611                 DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already "
612                            "pushed\n", (int)top_subreq->received,
613                            (int)state->pushed));
614
615                 status = state->sink((char *)top_subreq->buf,
616                                      top_subreq->received, state->priv);
617                 if (tevent_req_nterror(state->req, status)) {
618                         return;
619                 }
620                 state->pushed += top_subreq->received;
621
622                 TALLOC_FREE(state->reqs[state->top_req].req);
623
624                 if (state->requested < state->size) {
625                         struct tevent_req *new_req;
626                         off_t size_left;
627                         size_t request_thistime;
628
629                         size_left = state->size - state->requested;
630                         request_thistime = MIN(size_left, state->chunk_size);
631
632                         DEBUG(10, ("cli_pull_read_done: Requesting %d bytes "
633                                    "at %d, position %d\n",
634                                    (int)request_thistime,
635                                    (int)(state->start_offset
636                                          + state->requested),
637                                    state->top_req));
638
639                         new_req = cli_readall_send(
640                                 state->reqs, state->ev, state->cli,
641                                 state->fnum,
642                                 state->start_offset + state->requested,
643                                 request_thistime);
644
645                         if (tevent_req_nomem(new_req, state->req)) {
646                                 return;
647                         }
648                         tevent_req_set_callback(new_req, cli_pull_read_done,
649                                                 req);
650
651                         state->reqs[state->top_req].req = new_req;
652                         state->requested += request_thistime;
653                 }
654
655                 state->top_req = (state->top_req+1) % state->num_reqs;
656         }
657
658         tevent_req_done(req);
659 }
660
661 NTSTATUS cli_pull_recv(struct tevent_req *req, off_t *received)
662 {
663         struct cli_pull_state *state = tevent_req_data(
664                 req, struct cli_pull_state);
665         NTSTATUS status;
666
667         if (tevent_req_is_nterror(req, &status)) {
668                 return status;
669         }
670         *received = state->pushed;
671         return NT_STATUS_OK;
672 }
673
674 NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
675                   off_t start_offset, off_t size, size_t window_size,
676                   NTSTATUS (*sink)(char *buf, size_t n, void *priv),
677                   void *priv, off_t *received)
678 {
679         TALLOC_CTX *frame = talloc_stackframe();
680         struct tevent_context *ev;
681         struct tevent_req *req;
682         NTSTATUS status = NT_STATUS_OK;
683
684         if (smbXcli_conn_has_async_calls(cli->conn)) {
685                 /*
686                  * Can't use sync call while an async call is in flight
687                  */
688                 status = NT_STATUS_INVALID_PARAMETER;
689                 goto fail;
690         }
691
692         ev = samba_tevent_context_init(frame);
693         if (ev == NULL) {
694                 status = NT_STATUS_NO_MEMORY;
695                 goto fail;
696         }
697
698         req = cli_pull_send(frame, ev, cli, fnum, start_offset, size,
699                             window_size, sink, priv);
700         if (req == NULL) {
701                 status = NT_STATUS_NO_MEMORY;
702                 goto fail;
703         }
704
705         if (!tevent_req_poll(req, ev)) {
706                 status = map_nt_error_from_unix(errno);
707                 goto fail;
708         }
709
710         status = cli_pull_recv(req, received);
711  fail:
712         TALLOC_FREE(frame);
713         return status;
714 }
715
716 static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
717 {
718         char **pbuf = (char **)priv;
719         memcpy(*pbuf, buf, n);
720         *pbuf += n;
721         return NT_STATUS_OK;
722 }
723
724 NTSTATUS cli_read(struct cli_state *cli, uint16_t fnum,
725                  char *buf, off_t offset, size_t size,
726                  size_t *nread)
727 {
728         NTSTATUS status;
729         off_t ret;
730
731         status = cli_pull(cli, fnum, offset, size, size,
732                           cli_read_sink, &buf, &ret);
733         if (!NT_STATUS_IS_OK(status)) {
734                 return status;
735         }
736
737         if (nread) {
738                 *nread = ret;
739         }
740
741         return NT_STATUS_OK;
742 }
743
744 /****************************************************************************
745   write to a file using a SMBwrite and not bypassing 0 byte writes
746 ****************************************************************************/
747
748 NTSTATUS cli_smbwrite(struct cli_state *cli, uint16_t fnum, char *buf,
749                       off_t offset, size_t size1, size_t *ptotal)
750 {
751         uint8_t *bytes;
752         ssize_t total = 0;
753
754         /*
755          * 3 bytes prefix
756          */
757
758         bytes = talloc_array(talloc_tos(), uint8_t, 3);
759         if (bytes == NULL) {
760                 return NT_STATUS_NO_MEMORY;
761         }
762         bytes[0] = 1;
763
764         do {
765                 uint32_t usable_space = cli_state_available_size(cli, 48);
766                 size_t size = MIN(size1, usable_space);
767                 struct tevent_req *req;
768                 uint16_t vwv[5];
769                 uint16_t *ret_vwv;
770                 NTSTATUS status;
771
772                 SSVAL(vwv+0, 0, fnum);
773                 SSVAL(vwv+1, 0, size);
774                 SIVAL(vwv+2, 0, offset);
775                 SSVAL(vwv+4, 0, 0);
776
777                 bytes = talloc_realloc(talloc_tos(), bytes, uint8_t,
778                                              size+3);
779                 if (bytes == NULL) {
780                         return NT_STATUS_NO_MEMORY;
781                 }
782                 SSVAL(bytes, 1, size);
783                 memcpy(bytes + 3, buf + total, size);
784
785                 status = cli_smb(talloc_tos(), cli, SMBwrite, 0, 5, vwv,
786                                  size+3, bytes, &req, 1, NULL, &ret_vwv,
787                                  NULL, NULL);
788                 if (!NT_STATUS_IS_OK(status)) {
789                         TALLOC_FREE(bytes);
790                         return status;
791                 }
792
793                 size = SVAL(ret_vwv+0, 0);
794                 TALLOC_FREE(req);
795                 if (size == 0) {
796                         break;
797                 }
798                 size1 -= size;
799                 total += size;
800                 offset += size;
801
802         } while (size1);
803
804         TALLOC_FREE(bytes);
805
806         if (ptotal != NULL) {
807                 *ptotal = total;
808         }
809         return NT_STATUS_OK;
810 }
811
812 /*
813  * Send a write&x request
814  */
815
816 struct cli_write_andx_state {
817         size_t size;
818         uint16_t vwv[14];
819         size_t written;
820         uint8_t pad;
821         struct iovec iov[2];
822 };
823
824 static void cli_write_andx_done(struct tevent_req *subreq);
825
826 struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx,
827                                          struct tevent_context *ev,
828                                          struct cli_state *cli, uint16_t fnum,
829                                          uint16_t mode, const uint8_t *buf,
830                                          off_t offset, size_t size,
831                                          struct tevent_req **reqs_before,
832                                          int num_reqs_before,
833                                          struct tevent_req **psmbreq)
834 {
835         struct tevent_req *req, *subreq;
836         struct cli_write_andx_state *state;
837         bool bigoffset = ((smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES) != 0);
838         uint8_t wct = bigoffset ? 14 : 12;
839         size_t max_write = cli_write_max_bufsize(cli, mode, wct);
840         uint16_t *vwv;
841
842         req = tevent_req_create(mem_ctx, &state, struct cli_write_andx_state);
843         if (req == NULL) {
844                 return NULL;
845         }
846
847         state->size = MIN(size, max_write);
848
849         vwv = state->vwv;
850
851         SCVAL(vwv+0, 0, 0xFF);
852         SCVAL(vwv+0, 1, 0);
853         SSVAL(vwv+1, 0, 0);
854         SSVAL(vwv+2, 0, fnum);
855         SIVAL(vwv+3, 0, offset);
856         SIVAL(vwv+5, 0, 0);
857         SSVAL(vwv+7, 0, mode);
858         SSVAL(vwv+8, 0, 0);
859         SSVAL(vwv+9, 0, (state->size>>16));
860         SSVAL(vwv+10, 0, state->size);
861
862         SSVAL(vwv+11, 0,
863               smb1cli_req_wct_ofs(reqs_before, num_reqs_before)
864               + 1               /* the wct field */
865               + wct * 2         /* vwv */
866               + 2               /* num_bytes field */
867               + 1               /* pad */);
868
869         if (bigoffset) {
870                 SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
871         }
872
873         state->pad = 0;
874         state->iov[0].iov_base = (void *)&state->pad;
875         state->iov[0].iov_len = 1;
876         state->iov[1].iov_base = discard_const_p(void, buf);
877         state->iov[1].iov_len = state->size;
878
879         subreq = cli_smb_req_create(state, ev, cli, SMBwriteX, 0, wct, vwv,
880                                     2, state->iov);
881         if (tevent_req_nomem(subreq, req)) {
882                 return tevent_req_post(req, ev);
883         }
884         tevent_req_set_callback(subreq, cli_write_andx_done, req);
885         *psmbreq = subreq;
886         return req;
887 }
888
889 struct tevent_req *cli_write_andx_send(TALLOC_CTX *mem_ctx,
890                                        struct tevent_context *ev,
891                                        struct cli_state *cli, uint16_t fnum,
892                                        uint16_t mode, const uint8_t *buf,
893                                        off_t offset, size_t size)
894 {
895         struct tevent_req *req, *subreq;
896         NTSTATUS status;
897
898         req = cli_write_andx_create(mem_ctx, ev, cli, fnum, mode, buf, offset,
899                                     size, NULL, 0, &subreq);
900         if (req == NULL) {
901                 return NULL;
902         }
903
904         status = smb1cli_req_chain_submit(&subreq, 1);
905         if (tevent_req_nterror(req, status)) {
906                 return tevent_req_post(req, ev);
907         }
908         return req;
909 }
910
911 static void cli_write_andx_done(struct tevent_req *subreq)
912 {
913         struct tevent_req *req = tevent_req_callback_data(
914                 subreq, struct tevent_req);
915         struct cli_write_andx_state *state = tevent_req_data(
916                 req, struct cli_write_andx_state);
917         uint8_t wct;
918         uint16_t *vwv;
919         NTSTATUS status;
920
921         status = cli_smb_recv(subreq, state, NULL, 6, &wct, &vwv,
922                               NULL, NULL);
923         TALLOC_FREE(subreq);
924         if (NT_STATUS_IS_ERR(status)) {
925                 tevent_req_nterror(req, status);
926                 return;
927         }
928         state->written = SVAL(vwv+2, 0);
929         if (state->size > UINT16_MAX) {
930                 /*
931                  * It is important that we only set the
932                  * high bits only if we asked for a large write.
933                  *
934                  * OS/2 print shares get this wrong and may send
935                  * invalid values.
936                  *
937                  * See bug #5326.
938                  */
939                 state->written |= SVAL(vwv+4, 0)<<16;
940         }
941         tevent_req_done(req);
942 }
943
944 NTSTATUS cli_write_andx_recv(struct tevent_req *req, size_t *pwritten)
945 {
946         struct cli_write_andx_state *state = tevent_req_data(
947                 req, struct cli_write_andx_state);
948         NTSTATUS status;
949
950         if (tevent_req_is_nterror(req, &status)) {
951                 return status;
952         }
953         if (pwritten != 0) {
954                 *pwritten = state->written;
955         }
956         return NT_STATUS_OK;
957 }
958
959 struct cli_writeall_state {
960         struct tevent_context *ev;
961         struct cli_state *cli;
962         uint16_t fnum;
963         uint16_t mode;
964         const uint8_t *buf;
965         off_t offset;
966         size_t size;
967         size_t written;
968 };
969
970 static void cli_writeall_written(struct tevent_req *req);
971
972 static struct tevent_req *cli_writeall_send(TALLOC_CTX *mem_ctx,
973                                             struct tevent_context *ev,
974                                             struct cli_state *cli,
975                                             uint16_t fnum,
976                                             uint16_t mode,
977                                             const uint8_t *buf,
978                                             off_t offset, size_t size)
979 {
980         struct tevent_req *req, *subreq;
981         struct cli_writeall_state *state;
982
983         req = tevent_req_create(mem_ctx, &state, struct cli_writeall_state);
984         if (req == NULL) {
985                 return NULL;
986         }
987         state->ev = ev;
988         state->cli = cli;
989         state->fnum = fnum;
990         state->mode = mode;
991         state->buf = buf;
992         state->offset = offset;
993         state->size = size;
994         state->written = 0;
995
996         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
997                                      state->mode, state->buf, state->offset,
998                                      state->size);
999         if (tevent_req_nomem(subreq, req)) {
1000                 return tevent_req_post(req, ev);
1001         }
1002         tevent_req_set_callback(subreq, cli_writeall_written, req);
1003         return req;
1004 }
1005
1006 static void cli_writeall_written(struct tevent_req *subreq)
1007 {
1008         struct tevent_req *req = tevent_req_callback_data(
1009                 subreq, struct tevent_req);
1010         struct cli_writeall_state *state = tevent_req_data(
1011                 req, struct cli_writeall_state);
1012         NTSTATUS status;
1013         size_t written, to_write;
1014
1015         status = cli_write_andx_recv(subreq, &written);
1016         TALLOC_FREE(subreq);
1017         if (tevent_req_nterror(req, status)) {
1018                 return;
1019         }
1020
1021         state->written += written;
1022
1023         if (state->written > state->size) {
1024                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1025                 return;
1026         }
1027
1028         to_write = state->size - state->written;
1029
1030         if (to_write == 0) {
1031                 tevent_req_done(req);
1032                 return;
1033         }
1034
1035         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1036                                      state->mode,
1037                                      state->buf + state->written,
1038                                      state->offset + state->written, to_write);
1039         if (tevent_req_nomem(subreq, req)) {
1040                 return;
1041         }
1042         tevent_req_set_callback(subreq, cli_writeall_written, req);
1043 }
1044
1045 static NTSTATUS cli_writeall_recv(struct tevent_req *req,
1046                                   size_t *pwritten)
1047 {
1048         struct cli_writeall_state *state = tevent_req_data(
1049                 req, struct cli_writeall_state);
1050         NTSTATUS status;
1051
1052         if (tevent_req_is_nterror(req, &status)) {
1053                 return status;
1054         }
1055         if (pwritten != NULL) {
1056                 *pwritten = state->written;
1057         }
1058         return NT_STATUS_OK;
1059 }
1060
1061 NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1062                       const uint8_t *buf, off_t offset, size_t size,
1063                       size_t *pwritten)
1064 {
1065         TALLOC_CTX *frame = talloc_stackframe();
1066         struct tevent_context *ev;
1067         struct tevent_req *req;
1068         NTSTATUS status = NT_STATUS_NO_MEMORY;
1069
1070         if (smbXcli_conn_has_async_calls(cli->conn)) {
1071                 /*
1072                  * Can't use sync call while an async call is in flight
1073                  */
1074                 status = NT_STATUS_INVALID_PARAMETER;
1075                 goto fail;
1076         }
1077         ev = samba_tevent_context_init(frame);
1078         if (ev == NULL) {
1079                 goto fail;
1080         }
1081         req = cli_writeall_send(frame, ev, cli, fnum, mode, buf, offset, size);
1082         if (req == NULL) {
1083                 goto fail;
1084         }
1085         if (!tevent_req_poll(req, ev)) {
1086                 status = map_nt_error_from_unix(errno);
1087                 goto fail;
1088         }
1089         status = cli_writeall_recv(req, pwritten);
1090  fail:
1091         TALLOC_FREE(frame);
1092         return status;
1093 }
1094
1095 struct cli_push_write_state {
1096         struct tevent_req *req;/* This is the main request! Not the subreq */
1097         uint32_t idx;
1098         off_t ofs;
1099         uint8_t *buf;
1100         size_t size;
1101 };
1102
1103 struct cli_push_state {
1104         struct tevent_context *ev;
1105         struct cli_state *cli;
1106         uint16_t fnum;
1107         uint16_t mode;
1108         off_t start_offset;
1109         size_t window_size;
1110
1111         size_t (*source)(uint8_t *buf, size_t n, void *priv);
1112         void *priv;
1113
1114         bool eof;
1115
1116         size_t chunk_size;
1117         off_t next_offset;
1118
1119         /*
1120          * Outstanding requests
1121          */
1122         uint32_t pending;
1123         uint16_t max_reqs;
1124         uint32_t num_reqs;
1125         struct cli_push_write_state **reqs;
1126 };
1127
1128 static void cli_push_written(struct tevent_req *req);
1129
1130 static bool cli_push_write_setup(struct tevent_req *req,
1131                                  struct cli_push_state *state,
1132                                  uint32_t idx)
1133 {
1134         struct cli_push_write_state *substate;
1135         struct tevent_req *subreq;
1136
1137         substate = talloc(state->reqs, struct cli_push_write_state);
1138         if (!substate) {
1139                 return false;
1140         }
1141         substate->req = req;
1142         substate->idx = idx;
1143         substate->ofs = state->next_offset;
1144         substate->buf = talloc_array(substate, uint8_t, state->chunk_size);
1145         if (!substate->buf) {
1146                 talloc_free(substate);
1147                 return false;
1148         }
1149         substate->size = state->source(substate->buf,
1150                                        state->chunk_size,
1151                                        state->priv);
1152         if (substate->size == 0) {
1153                 state->eof = true;
1154                 /* nothing to send */
1155                 talloc_free(substate);
1156                 return true;
1157         }
1158
1159         subreq = cli_writeall_send(substate,
1160                                    state->ev, state->cli,
1161                                    state->fnum, state->mode,
1162                                    substate->buf,
1163                                    substate->ofs,
1164                                    substate->size);
1165         if (!subreq) {
1166                 talloc_free(substate);
1167                 return false;
1168         }
1169         tevent_req_set_callback(subreq, cli_push_written, substate);
1170
1171         state->reqs[idx] = substate;
1172         state->pending += 1;
1173         state->next_offset += substate->size;
1174
1175         return true;
1176 }
1177
1178 struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1179                                  struct cli_state *cli,
1180                                  uint16_t fnum, uint16_t mode,
1181                                  off_t start_offset, size_t window_size,
1182                                  size_t (*source)(uint8_t *buf, size_t n,
1183                                                   void *priv),
1184                                  void *priv)
1185 {
1186         struct tevent_req *req;
1187         struct cli_push_state *state;
1188         uint32_t i;
1189         size_t page_size = 1024;
1190
1191         req = tevent_req_create(mem_ctx, &state, struct cli_push_state);
1192         if (req == NULL) {
1193                 return NULL;
1194         }
1195         state->cli = cli;
1196         state->ev = ev;
1197         state->fnum = fnum;
1198         state->start_offset = start_offset;
1199         state->mode = mode;
1200         state->source = source;
1201         state->priv = priv;
1202         state->eof = false;
1203         state->pending = 0;
1204         state->next_offset = start_offset;
1205
1206         state->chunk_size = cli_write_max_bufsize(cli, mode, 14);
1207         if (state->chunk_size > page_size) {
1208                 state->chunk_size &= ~(page_size - 1);
1209         }
1210
1211         state->max_reqs = smbXcli_conn_max_requests(cli->conn);
1212
1213         if (window_size == 0) {
1214                 window_size = state->max_reqs * state->chunk_size;
1215         }
1216         state->num_reqs = window_size/state->chunk_size;
1217         if ((window_size % state->chunk_size) > 0) {
1218                 state->num_reqs += 1;
1219         }
1220         state->num_reqs = MIN(state->num_reqs, state->max_reqs);
1221         state->num_reqs = MAX(state->num_reqs, 1);
1222
1223         state->reqs = talloc_zero_array(state, struct cli_push_write_state *,
1224                                         state->num_reqs);
1225         if (state->reqs == NULL) {
1226                 goto failed;
1227         }
1228
1229         for (i=0; i<state->num_reqs; i++) {
1230                 if (!cli_push_write_setup(req, state, i)) {
1231                         goto failed;
1232                 }
1233
1234                 if (state->eof) {
1235                         break;
1236                 }
1237         }
1238
1239         if (state->pending == 0) {
1240                 tevent_req_done(req);
1241                 return tevent_req_post(req, ev);
1242         }
1243
1244         return req;
1245
1246  failed:
1247         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1248         return tevent_req_post(req, ev);
1249 }
1250
1251 static void cli_push_written(struct tevent_req *subreq)
1252 {
1253         struct cli_push_write_state *substate = tevent_req_callback_data(
1254                 subreq, struct cli_push_write_state);
1255         struct tevent_req *req = substate->req;
1256         struct cli_push_state *state = tevent_req_data(
1257                 req, struct cli_push_state);
1258         NTSTATUS status;
1259         uint32_t idx = substate->idx;
1260
1261         state->reqs[idx] = NULL;
1262         state->pending -= 1;
1263
1264         status = cli_writeall_recv(subreq, NULL);
1265         TALLOC_FREE(subreq);
1266         TALLOC_FREE(substate);
1267         if (tevent_req_nterror(req, status)) {
1268                 return;
1269         }
1270
1271         if (!state->eof) {
1272                 if (!cli_push_write_setup(req, state, idx)) {
1273                         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1274                         return;
1275                 }
1276         }
1277
1278         if (state->pending == 0) {
1279                 tevent_req_done(req);
1280                 return;
1281         }
1282 }
1283
1284 NTSTATUS cli_push_recv(struct tevent_req *req)
1285 {
1286         return tevent_req_simple_recv_ntstatus(req);
1287 }
1288
1289 NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1290                   off_t start_offset, size_t window_size,
1291                   size_t (*source)(uint8_t *buf, size_t n, void *priv),
1292                   void *priv)
1293 {
1294         TALLOC_CTX *frame = talloc_stackframe();
1295         struct tevent_context *ev;
1296         struct tevent_req *req;
1297         NTSTATUS status = NT_STATUS_OK;
1298
1299         if (smbXcli_conn_has_async_calls(cli->conn)) {
1300                 /*
1301                  * Can't use sync call while an async call is in flight
1302                  */
1303                 status = NT_STATUS_INVALID_PARAMETER;
1304                 goto fail;
1305         }
1306
1307         ev = samba_tevent_context_init(frame);
1308         if (ev == NULL) {
1309                 status = NT_STATUS_NO_MEMORY;
1310                 goto fail;
1311         }
1312
1313         req = cli_push_send(frame, ev, cli, fnum, mode, start_offset,
1314                             window_size, source, priv);
1315         if (req == NULL) {
1316                 status = NT_STATUS_NO_MEMORY;
1317                 goto fail;
1318         }
1319
1320         if (!tevent_req_poll(req, ev)) {
1321                 status = map_nt_error_from_unix(errno);
1322                 goto fail;
1323         }
1324
1325         status = cli_push_recv(req);
1326  fail:
1327         TALLOC_FREE(frame);
1328         return status;
1329 }