Talloc doc: Fix a cut&paste error
[Samba/gebeck_regimport.git] / source3 / libsmb / clisymlink.c
blob9e21d1b88372ad0080c6de29b142121dbe0aeb78
1 /*
2 * Unix SMB/CIFS implementation.
3 * Client implementation of setting symlinks using reparse points
4 * Copyright (C) Volker Lendecke 2011
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.
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.
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/>.
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "libsmb/libsmb.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "async_smb.h"
25 #include "libsmb/clirap.h"
26 #include "trans2.h"
27 #include "libcli/security/secdesc.h"
28 #include "libcli/security/security.h"
30 struct cli_symlink_state {
31 struct tevent_context *ev;
32 struct cli_state *cli;
33 const char *oldpath;
34 const char *newpath;
35 uint32_t flags;
37 uint16_t fnum;
39 uint16_t setup[4];
40 NTSTATUS set_reparse_status;
43 static void cli_symlink_create_done(struct tevent_req *subreq);
44 static void cli_symlink_set_reparse_done(struct tevent_req *subreq);
45 static void cli_symlink_delete_on_close_done(struct tevent_req *subreq);
46 static void cli_symlink_close_done(struct tevent_req *subreq);
48 struct tevent_req *cli_symlink_send(TALLOC_CTX *mem_ctx,
49 struct tevent_context *ev,
50 struct cli_state *cli,
51 const char *oldpath,
52 const char *newpath,
53 uint32_t flags)
55 struct tevent_req *req, *subreq;
56 struct cli_symlink_state *state;
58 req = tevent_req_create(mem_ctx, &state, struct cli_symlink_state);
59 if (req == NULL) {
60 return NULL;
62 state->ev = ev;
63 state->cli = cli;
64 state->oldpath = oldpath;
65 state->newpath = newpath;
66 state->flags = flags;
68 subreq = cli_ntcreate_send(
69 state, ev, cli, state->oldpath, 0,
70 SYNCHRONIZE_ACCESS|DELETE_ACCESS|
71 FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
72 FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE, FILE_CREATE,
73 FILE_OPEN_REPARSE_POINT|FILE_SYNCHRONOUS_IO_NONALERT|
74 FILE_NON_DIRECTORY_FILE, 0);
75 if (tevent_req_nomem(subreq, req)) {
76 return tevent_req_post(req, ev);
78 tevent_req_set_callback(subreq, cli_symlink_create_done, req);
79 return req;
82 static void cli_symlink_create_done(struct tevent_req *subreq)
84 struct tevent_req *req = tevent_req_callback_data(
85 subreq, struct tevent_req);
86 struct cli_symlink_state *state = tevent_req_data(
87 req, struct cli_symlink_state);
88 uint8_t *data;
89 size_t data_len;
90 NTSTATUS status;
92 status = cli_ntcreate_recv(subreq, &state->fnum);
93 TALLOC_FREE(subreq);
94 if (tevent_req_nterror(req, status)) {
95 return;
98 SIVAL(state->setup, 0, FSCTL_SET_REPARSE_POINT);
99 SSVAL(state->setup, 4, state->fnum);
100 SCVAL(state->setup, 6, 1); /* IsFcntl */
101 SCVAL(state->setup, 7, 0); /* IsFlags */
103 if (!symlink_reparse_buffer_marshall(
104 state->newpath, NULL, state->flags, state,
105 &data, &data_len)) {
106 tevent_req_oom(req);
107 return;
110 subreq = cli_trans_send(state, state->ev, state->cli, SMBnttrans,
111 NULL, -1, /* name, fid */
112 NT_TRANSACT_IOCTL, 0,
113 state->setup, 4, 0, /* setup */
114 NULL, 0, 0, /* param */
115 data, data_len, 0); /* data */
116 if (tevent_req_nomem(subreq, req)) {
117 return;
119 tevent_req_set_callback(subreq, cli_symlink_set_reparse_done, req);
122 static void cli_symlink_set_reparse_done(struct tevent_req *subreq)
124 struct tevent_req *req = tevent_req_callback_data(
125 subreq, struct tevent_req);
126 struct cli_symlink_state *state = tevent_req_data(
127 req, struct cli_symlink_state);
129 state->set_reparse_status = cli_trans_recv(
130 subreq, NULL, NULL,
131 NULL, 0, NULL, /* rsetup */
132 NULL, 0, NULL, /* rparam */
133 NULL, 0, NULL); /* rdata */
134 TALLOC_FREE(subreq);
136 if (NT_STATUS_IS_OK(state->set_reparse_status)) {
137 subreq = cli_close_send(state, state->ev, state->cli,
138 state->fnum);
139 if (tevent_req_nomem(subreq, req)) {
140 return;
142 tevent_req_set_callback(subreq, cli_symlink_close_done, req);
143 return;
145 subreq = cli_nt_delete_on_close_send(
146 state, state->ev, state->cli, state->fnum, true);
147 if (tevent_req_nomem(subreq, req)) {
148 return;
150 tevent_req_set_callback(subreq, cli_symlink_delete_on_close_done, req);
153 static void cli_symlink_delete_on_close_done(struct tevent_req *subreq)
155 struct tevent_req *req = tevent_req_callback_data(
156 subreq, struct tevent_req);
157 struct cli_symlink_state *state = tevent_req_data(
158 req, struct cli_symlink_state);
161 * Ignore status, we can't do much anyway in case of failure
164 (void)cli_nt_delete_on_close_recv(subreq);
165 TALLOC_FREE(subreq);
167 subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
168 if (tevent_req_nomem(subreq, req)) {
169 return;
171 tevent_req_set_callback(subreq, cli_symlink_close_done, req);
174 static void cli_symlink_close_done(struct tevent_req *subreq)
176 struct tevent_req *req = tevent_req_callback_data(
177 subreq, struct tevent_req);
178 struct cli_symlink_state *state = tevent_req_data(
179 req, struct cli_symlink_state);
180 NTSTATUS status;
182 status = cli_close_recv(subreq);
183 TALLOC_FREE(subreq);
185 if (tevent_req_nterror(req, status)) {
186 return;
188 if (tevent_req_nterror(req, state->set_reparse_status)) {
189 return;
191 tevent_req_done(req);
194 NTSTATUS cli_symlink_recv(struct tevent_req *req)
196 return tevent_req_simple_recv_ntstatus(req);
199 NTSTATUS cli_symlink(struct cli_state *cli, const char *oldname,
200 const char *newname, uint32_t flags)
202 TALLOC_CTX *frame = talloc_stackframe();
203 struct event_context *ev;
204 struct tevent_req *req;
205 NTSTATUS status = NT_STATUS_NO_MEMORY;
207 if (cli_has_async_calls(cli)) {
208 status = NT_STATUS_INVALID_PARAMETER;
209 goto fail;
211 ev = event_context_init(frame);
212 if (ev == NULL) {
213 goto fail;
215 req = cli_symlink_send(frame, ev, cli, oldname, newname, flags);
216 if (req == NULL) {
217 goto fail;
219 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
220 goto fail;
222 status = cli_symlink_recv(req);
223 fail:
224 TALLOC_FREE(frame);
225 return status;
228 struct cli_readlink_state {
229 struct tevent_context *ev;
230 struct cli_state *cli;
231 uint16_t fnum;
233 uint16_t setup[4];
234 NTSTATUS get_reparse_status;
235 uint8_t *data;
236 uint32_t num_data;
239 static void cli_readlink_opened(struct tevent_req *subreq);
240 static void cli_readlink_got_reparse_data(struct tevent_req *subreq);
241 static void cli_readlink_closed(struct tevent_req *subreq);
243 struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
244 struct tevent_context *ev,
245 struct cli_state *cli,
246 const char *fname)
248 struct tevent_req *req, *subreq;
249 struct cli_readlink_state *state;
251 req = tevent_req_create(mem_ctx, &state, struct cli_readlink_state);
252 if (req == NULL) {
253 return NULL;
255 state->ev = ev;
256 state->cli = cli;
258 subreq = cli_ntcreate_send(
259 state, ev, cli, fname, 0, FILE_READ_ATTRIBUTES | FILE_READ_EA,
260 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
261 FILE_OPEN, FILE_OPEN_REPARSE_POINT, 0);
262 if (tevent_req_nomem(subreq, req)) {
263 return tevent_req_post(req, ev);
265 tevent_req_set_callback(subreq, cli_readlink_opened, req);
266 return req;
269 static void cli_readlink_opened(struct tevent_req *subreq)
271 struct tevent_req *req = tevent_req_callback_data(
272 subreq, struct tevent_req);
273 struct cli_readlink_state *state = tevent_req_data(
274 req, struct cli_readlink_state);
275 NTSTATUS status;
277 status = cli_ntcreate_recv(subreq, &state->fnum);
278 TALLOC_FREE(subreq);
279 if (tevent_req_nterror(req, status)) {
280 return;
283 SIVAL(state->setup, 0, FSCTL_GET_REPARSE_POINT);
284 SSVAL(state->setup, 4, state->fnum);
285 SCVAL(state->setup, 6, 1); /* IsFcntl */
286 SCVAL(state->setup, 7, 0); /* IsFlags */
288 subreq = cli_trans_send(state, state->ev, state->cli, SMBnttrans,
289 NULL, -1, /* name, fid */
290 NT_TRANSACT_IOCTL, 0,
291 state->setup, 4, 0, /* setup */
292 NULL, 0, 0, /* param */
293 NULL, 0, 16384); /* data */
294 if (tevent_req_nomem(subreq, req)) {
295 return;
297 tevent_req_set_callback(subreq, cli_readlink_got_reparse_data, req);
300 static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
302 struct tevent_req *req = tevent_req_callback_data(
303 subreq, struct tevent_req);
304 struct cli_readlink_state *state = tevent_req_data(
305 req, struct cli_readlink_state);
307 state->get_reparse_status = cli_trans_recv(
308 subreq, state, NULL,
309 NULL, 0, NULL, /* rsetup */
310 NULL, 0, NULL, /* rparam */
311 &state->data, 20, &state->num_data); /* rdata */
312 TALLOC_FREE(subreq);
314 subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
315 if (tevent_req_nomem(subreq, req)) {
316 return;
318 tevent_req_set_callback(subreq, cli_readlink_closed, req);
321 static void cli_readlink_closed(struct tevent_req *subreq)
323 struct tevent_req *req = tevent_req_callback_data(
324 subreq, struct tevent_req);
325 NTSTATUS status;
327 status = cli_close_recv(subreq);
328 TALLOC_FREE(subreq);
329 if (tevent_req_nterror(req, status)) {
330 return;
332 tevent_req_done(req);
335 NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
336 char **psubstitute_name, char **pprint_name,
337 uint32_t *pflags)
339 struct cli_readlink_state *state = tevent_req_data(
340 req, struct cli_readlink_state);
341 NTSTATUS status;
342 char *substitute_name;
343 char *print_name;
344 uint32_t flags;
346 if (tevent_req_is_nterror(req, &status)) {
347 return status;
350 if (!symlink_reparse_buffer_parse(state->data, state->num_data,
351 talloc_tos(), &substitute_name,
352 &print_name, &flags)) {
353 return NT_STATUS_INVALID_NETWORK_RESPONSE;
356 if (psubstitute_name != NULL) {
357 *psubstitute_name = talloc_move(mem_ctx, &substitute_name);
359 TALLOC_FREE(substitute_name);
361 if (pprint_name != NULL) {
362 *pprint_name = talloc_move(mem_ctx, &print_name);
364 TALLOC_FREE(print_name);
366 if (pflags != NULL) {
367 *pflags = flags;
369 return NT_STATUS_OK;
372 NTSTATUS cli_readlink(struct cli_state *cli, const char *fname,
373 TALLOC_CTX *mem_ctx, char **psubstitute_name,
374 char **pprint_name, uint32_t *pflags)
376 TALLOC_CTX *frame = talloc_stackframe();
377 struct event_context *ev;
378 struct tevent_req *req;
379 NTSTATUS status = NT_STATUS_NO_MEMORY;
381 if (cli_has_async_calls(cli)) {
382 status = NT_STATUS_INVALID_PARAMETER;
383 goto fail;
385 ev = event_context_init(frame);
386 if (ev == NULL) {
387 goto fail;
389 req = cli_readlink_send(frame, ev, cli, fname);
390 if (req == NULL) {
391 goto fail;
393 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
394 goto fail;
396 status = cli_readlink_recv(req, mem_ctx, psubstitute_name,
397 pprint_name, pflags);
398 fail:
399 TALLOC_FREE(frame);
400 return status;