~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/libcli/smb_composite/savefile.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
 
 
4
   Copyright (C) Andrew Tridgell 2005
 
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
  a composite API for saving a whole file from memory
 
21
*/
 
22
 
 
23
#include "includes.h"
 
24
#include "libcli/raw/libcliraw.h"
 
25
#include "libcli/raw/raw_proto.h"
 
26
#include "libcli/composite/composite.h"
 
27
#include "libcli/smb_composite/smb_composite.h"
 
28
 
 
29
/* the stages of this call */
 
30
enum savefile_stage {SAVEFILE_OPEN, SAVEFILE_WRITE, SAVEFILE_CLOSE};
 
31
 
 
32
static void savefile_handler(struct smbcli_request *req);
 
33
 
 
34
struct savefile_state {
 
35
        enum savefile_stage stage;
 
36
        off_t total_written;
 
37
        struct smb_composite_savefile *io;
 
38
        union smb_open *io_open;
 
39
        union smb_write *io_write;
 
40
        struct smbcli_request *req;
 
41
};
 
42
 
 
43
 
 
44
/*
 
45
  setup for the close
 
46
*/
 
47
static NTSTATUS setup_close(struct composite_context *c, 
 
48
                            struct smbcli_tree *tree, uint16_t fnum)
 
49
{
 
50
        struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
 
51
        union smb_close *io_close;
 
52
 
 
53
        /* nothing to write, setup the close */
 
54
        io_close = talloc(c, union smb_close);
 
55
        NT_STATUS_HAVE_NO_MEMORY(io_close);
 
56
        
 
57
        io_close->close.level = RAW_CLOSE_CLOSE;
 
58
        io_close->close.in.file.fnum = fnum;
 
59
        io_close->close.in.write_time = 0;
 
60
 
 
61
        state->req = smb_raw_close_send(tree, io_close);
 
62
        NT_STATUS_HAVE_NO_MEMORY(state->req);
 
63
 
 
64
        /* call the handler again when the close is done */
 
65
        state->stage = SAVEFILE_CLOSE;
 
66
        state->req->async.fn = savefile_handler;
 
67
        state->req->async.private_data = c;
 
68
 
 
69
        return NT_STATUS_OK;
 
70
}
 
71
 
 
72
/*
 
73
  called when the open is done - pull the results and setup for the
 
74
  first writex, or close if the file is zero size
 
75
*/
 
76
static NTSTATUS savefile_open(struct composite_context *c, 
 
77
                              struct smb_composite_savefile *io)
 
78
{
 
79
        struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
 
80
        union smb_write *io_write;
 
81
        struct smbcli_tree *tree = state->req->tree;
 
82
        NTSTATUS status;
 
83
        uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
 
84
 
 
85
        status = smb_raw_open_recv(state->req, c, state->io_open);
 
86
        NT_STATUS_NOT_OK_RETURN(status);
 
87
        
 
88
        if (io->in.size == 0) {
 
89
                return setup_close(c, tree, state->io_open->ntcreatex.out.file.fnum);
 
90
        }
 
91
 
 
92
        /* setup for the first write */
 
93
        io_write = talloc(c, union smb_write);
 
94
        NT_STATUS_HAVE_NO_MEMORY(io_write);
 
95
        
 
96
        io_write->writex.level        = RAW_WRITE_WRITEX;
 
97
        io_write->writex.in.file.fnum = state->io_open->ntcreatex.out.file.fnum;
 
98
        io_write->writex.in.offset    = 0;
 
99
        io_write->writex.in.wmode     = 0;
 
100
        io_write->writex.in.remaining = 0;
 
101
        io_write->writex.in.count     = MIN(max_xmit - 100, io->in.size);
 
102
        io_write->writex.in.data      = io->in.data;
 
103
        state->io_write = io_write;
 
104
 
 
105
        state->req = smb_raw_write_send(tree, io_write);
 
106
        NT_STATUS_HAVE_NO_MEMORY(state->req);
 
107
 
 
108
        /* call the handler again when the first write is done */
 
109
        state->stage = SAVEFILE_WRITE;
 
110
        state->req->async.fn = savefile_handler;
 
111
        state->req->async.private_data = c;
 
112
        talloc_free(state->io_open);
 
113
 
 
114
        return NT_STATUS_OK;
 
115
}
 
116
 
 
117
 
 
118
/*
 
119
  called when a write is done - pull the results and setup for the
 
120
  next write, or close if the file is all done
 
121
*/
 
122
static NTSTATUS savefile_write(struct composite_context *c, 
 
123
                              struct smb_composite_savefile *io)
 
124
{
 
125
        struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
 
126
        struct smbcli_tree *tree = state->req->tree;
 
127
        NTSTATUS status;
 
128
        uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
 
129
 
 
130
        status = smb_raw_write_recv(state->req, state->io_write);
 
131
        NT_STATUS_NOT_OK_RETURN(status);
 
132
 
 
133
        state->total_written += state->io_write->writex.out.nwritten;
 
134
        
 
135
        /* we might be done */
 
136
        if (state->io_write->writex.out.nwritten != state->io_write->writex.in.count ||
 
137
            state->total_written == io->in.size) {
 
138
                return setup_close(c, tree, state->io_write->writex.in.file.fnum);
 
139
        }
 
140
 
 
141
        /* setup for the next write */
 
142
        state->io_write->writex.in.offset = state->total_written;
 
143
        state->io_write->writex.in.count = MIN(max_xmit - 100, 
 
144
                                               io->in.size - state->total_written);
 
145
        state->io_write->writex.in.data = io->in.data + state->total_written;
 
146
 
 
147
        state->req = smb_raw_write_send(tree, state->io_write);
 
148
        NT_STATUS_HAVE_NO_MEMORY(state->req);
 
149
 
 
150
        /* call the handler again when the write is done */
 
151
        state->req->async.fn = savefile_handler;
 
152
        state->req->async.private_data = c;
 
153
 
 
154
        return NT_STATUS_OK;
 
155
}
 
156
 
 
157
/*
 
158
  called when the close is done, check the status and cleanup
 
159
*/
 
160
static NTSTATUS savefile_close(struct composite_context *c, 
 
161
                               struct smb_composite_savefile *io)
 
162
{
 
163
        struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
 
164
        NTSTATUS status;
 
165
 
 
166
        status = smbcli_request_simple_recv(state->req);
 
167
        NT_STATUS_NOT_OK_RETURN(status);
 
168
 
 
169
        if (state->total_written != io->in.size) {
 
170
                return NT_STATUS_DISK_FULL;
 
171
        }
 
172
        
 
173
        c->state = COMPOSITE_STATE_DONE;
 
174
 
 
175
        return NT_STATUS_OK;
 
176
}
 
177
                                                     
 
178
 
 
179
/*
 
180
  handler for completion of a sub-request in savefile
 
181
*/
 
182
static void savefile_handler(struct smbcli_request *req)
 
183
{
 
184
        struct composite_context *c = (struct composite_context *)req->async.private_data;
 
185
        struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
 
186
 
 
187
        /* when this handler is called, the stage indicates what
 
188
           call has just finished */
 
189
        switch (state->stage) {
 
190
        case SAVEFILE_OPEN:
 
191
                c->status = savefile_open(c, state->io);
 
192
                break;
 
193
 
 
194
        case SAVEFILE_WRITE:
 
195
                c->status = savefile_write(c, state->io);
 
196
                break;
 
197
 
 
198
        case SAVEFILE_CLOSE:
 
199
                c->status = savefile_close(c, state->io);
 
200
                break;
 
201
        }
 
202
 
 
203
        if (!NT_STATUS_IS_OK(c->status)) {
 
204
                c->state = COMPOSITE_STATE_ERROR;
 
205
        }
 
206
 
 
207
        if (c->state >= COMPOSITE_STATE_DONE &&
 
208
            c->async.fn) {
 
209
                c->async.fn(c);
 
210
        }
 
211
}
 
212
 
 
213
/*
 
214
  composite savefile call - does an openx followed by a number of writex calls,
 
215
  followed by a close
 
216
*/
 
217
struct composite_context *smb_composite_savefile_send(struct smbcli_tree *tree, 
 
218
                                                      struct smb_composite_savefile *io)
 
219
{
 
220
        struct composite_context *c;
 
221
        struct savefile_state *state;
 
222
        union smb_open *io_open;
 
223
 
 
224
        c = talloc_zero(tree, struct composite_context);
 
225
        if (c == NULL) goto failed;
 
226
 
 
227
        c->state = COMPOSITE_STATE_IN_PROGRESS;
 
228
        c->event_ctx = tree->session->transport->socket->event.ctx;
 
229
 
 
230
        state = talloc(c, struct savefile_state);
 
231
        if (state == NULL) goto failed;
 
232
 
 
233
        state->stage = SAVEFILE_OPEN;
 
234
        state->total_written = 0;
 
235
        state->io = io;
 
236
 
 
237
        /* setup for the open */
 
238
        io_open = talloc_zero(c, union smb_open);
 
239
        if (io_open == NULL) goto failed;
 
240
        
 
241
        io_open->ntcreatex.level               = RAW_OPEN_NTCREATEX;
 
242
        io_open->ntcreatex.in.flags            = NTCREATEX_FLAGS_EXTENDED;
 
243
        io_open->ntcreatex.in.access_mask      = SEC_FILE_WRITE_DATA;
 
244
        io_open->ntcreatex.in.file_attr        = FILE_ATTRIBUTE_NORMAL;
 
245
        io_open->ntcreatex.in.share_access     = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
 
246
        io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
 
247
        io_open->ntcreatex.in.impersonation    = NTCREATEX_IMPERSONATION_ANONYMOUS;
 
248
        io_open->ntcreatex.in.fname            = io->in.fname;
 
249
        state->io_open = io_open;
 
250
 
 
251
        /* send the open on its way */
 
252
        state->req = smb_raw_open_send(tree, io_open);
 
253
        if (state->req == NULL) goto failed;
 
254
 
 
255
        /* setup the callback handler */
 
256
        state->req->async.fn = savefile_handler;
 
257
        state->req->async.private_data = c;
 
258
        c->private_data = state;
 
259
 
 
260
        return c;
 
261
 
 
262
failed:
 
263
        talloc_free(c);
 
264
        return NULL;
 
265
}
 
266
 
 
267
 
 
268
/*
 
269
  composite savefile call - recv side
 
270
*/
 
271
NTSTATUS smb_composite_savefile_recv(struct composite_context *c)
 
272
{
 
273
        NTSTATUS status;
 
274
        status = composite_wait(c);
 
275
        talloc_free(c);
 
276
        return status;
 
277
}
 
278
 
 
279
 
 
280
/*
 
281
  composite savefile call - sync interface
 
282
*/
 
283
NTSTATUS smb_composite_savefile(struct smbcli_tree *tree, 
 
284
                                struct smb_composite_savefile *io)
 
285
{
 
286
        struct composite_context *c = smb_composite_savefile_send(tree, io);
 
287
        return smb_composite_savefile_recv(c);
 
288
}