s3: Add cli_shadow_copy_data
authorVolker Lendecke <vl@samba.org>
Mon, 29 Nov 2010 16:39:43 +0000 (17:39 +0100)
committerVolker Lendecke <vl@samba.org>
Fri, 10 Dec 2010 13:36:21 +0000 (14:36 +0100)
source3/include/proto.h
source3/libsmb/clifile.c

index b4bc97731dbca85e149a252d4a01e4eb608dfa6f..75d83b80ed0c79d5b1a84719bb1044f7b0648236 100644 (file)
@@ -2713,6 +2713,17 @@ bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
 bool cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen);
 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name);
 
+struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct cli_state *cli,
+                                            uint16_t fnum,
+                                            bool get_names);
+NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                                  char ***pnames, int *pnum_names);
+NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+                             uint16_t fnum, bool get_names,
+                             char ***pnames, int *pnum_names);
+
 /* The following definitions come from libsmb/clirap2.c  */
 
 int cli_NetGroupDelete(struct cli_state *cli, const char *group_name);
index 0bb1e1aef89bce68cb0831ddb75f9dee6742f857..83faf940c1c04c86fb4220158320d14c868abf21 100644 (file)
@@ -2419,3 +2419,159 @@ int cli_posix_rmdir(struct cli_state *cli, const char *fname)
 {
        return cli_posix_unlink_internal(cli, fname, True);
 }
+
+struct cli_shadow_copy_data_state {
+       uint16_t setup[4];
+       uint8_t *data;
+       uint32_t num_data;
+       bool get_names;
+};
+
+static void cli_shadow_copy_data_done(struct async_req *subreq);
+
+struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct cli_state *cli,
+                                            uint16_t fnum,
+                                            bool get_names)
+{
+       struct tevent_req *req;
+       struct async_req *subreq;
+       struct cli_shadow_copy_data_state *state;
+       uint32_t ret_size;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_shadow_copy_data_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->get_names = get_names;
+       ret_size = get_names ? cli->max_xmit : 16;
+
+       SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
+       SSVAL(state->setup + 2, 0, fnum);
+       SCVAL(state->setup + 3, 0, 0); /* isFsctl */
+       SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
+
+       subreq = cli_trans_send(
+               state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
+               state->setup, ARRAY_SIZE(state->setup), 0,
+               NULL, 0, 0,
+               NULL, 0, ret_size);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       subreq->async.fn = cli_shadow_copy_data_done;
+       subreq->async.priv = req;
+       return req;
+}
+
+static void cli_shadow_copy_data_done(struct async_req *subreq)
+{
+       struct tevent_req *req = talloc_get_type_abort(
+               subreq->async.priv, struct tevent_req);
+       struct cli_shadow_copy_data_state *state = tevent_req_data(
+               req, struct cli_shadow_copy_data_state);
+       NTSTATUS status;
+
+       status = cli_trans_recv(subreq, state,
+                               NULL, NULL, /* setup */
+                               NULL, NULL, /* param */
+                               &state->data, &state->num_data);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+       if (state->num_data < 12) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                                  char ***pnames, int *pnum_names)
+{
+       struct cli_shadow_copy_data_state *state = tevent_req_data(
+               req, struct cli_shadow_copy_data_state);
+       char **names;
+       int i, num_names;
+       uint32_t dlength;
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       num_names = IVAL(state->data, 4);
+       dlength = IVAL(state->data, 8);
+
+       if (!state->get_names) {
+               *pnum_names = num_names;
+               return NT_STATUS_OK;
+       }
+
+       if (dlength+12 > state->num_data) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+       names = talloc_array(mem_ctx, char *, num_names);
+       if (names == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i=0; i<num_names; i++) {
+               bool ret;
+               uint8_t *src;
+               size_t converted_size;
+
+               src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
+               ret = convert_string_talloc(
+                       names, CH_UTF16LE, CH_UNIX,
+                       src, 2 * sizeof(SHADOW_COPY_LABEL),
+                       &names[i], &converted_size, True);
+               if (!ret) {
+                       TALLOC_FREE(names);
+                       return NT_STATUS_INVALID_NETWORK_RESPONSE;
+               }
+       }
+       *pnum_names = num_names;
+       *pnames = names;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+                             uint16_t fnum, bool get_names,
+                             char ***pnames, int *pnum_names)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       if (cli->fd_event != NULL) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll(req, ev)) {
+               status = map_nt_error_from_unix(errno);
+               goto fail;
+       }
+       status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
+ fail:
+       TALLOC_FREE(frame);
+       if (!NT_STATUS_IS_OK(status)) {
+               cli_set_error(cli, status);
+       }
+       return status;
+}