~ubuntu-branches/ubuntu/oneiric/samba/oneiric-security

« back to all changes in this revision

Viewing changes to .pc/bug_605728_upstream_7791.patch/source3/libsmb/clireadwrite.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2010-12-08 00:16:04 UTC
  • mfrom: (0.39.7 sid)
  • Revision ID: james.westby@ubuntu.com-20101208001604-sv2xvi0e8n2z89hl
Tags: 2:3.5.6~dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access. 
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/mksmbpasswd.awk:
    - Do not add user with UID less than 1000 to smbpasswd
  + debian/control:
    - Make libwbclient0 replace/conflict with hardy's likewise-open.
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
    - Add cuups breaks to push the package to aslo upgrade cups (LP: #639768)
  + debian/rules:
    - enable "native" PIE hardening.
    - Add BIND_NOW to maximize benefit of RELRO hardening.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
    - Don't ship the /etc/network/if-up.d file.
  + debian/samba.postinst: 
    - Fixed bashism.
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/samba.logrotate: Make it upstart compatible
  + debian/samba-common.dhcp: Fix typo to get a proper parsing in
    /etc/samba/dhcp.
  + Dropped:
    - debian/patches/fix-lpbug-393012.patch: Dropped in favor of debian's patch.

Show diffs side-by-side

added added

removed removed

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