summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2019-03-18 10:34:53 +0100
committerJeremy Allison <jra@samba.org>2019-03-20 22:07:45 +0000
commitb5af004b23541550f46ef9b8fcaf5cb045f9da25 (patch)
treea68761433f73b510a08bb9354e5b8c16ead46991
parentb4c87b09b6630e29f8f0a7e4533acee63839d899 (diff)
downloadsamba-b5af004b23541550f46ef9b8fcaf5cb045f9da25.tar.gz
libsmb: Introduce protocol-agnostic cli_hardlink
Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
-rw-r--r--source3/libsmb/clifile.c237
-rw-r--r--source3/libsmb/proto.h12
2 files changed, 248 insertions, 1 deletions
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index e4eb3f286f9..0ceffe8bce7 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -26,7 +26,7 @@
#include "libsmb/clirap.h"
#include "trans2.h"
#include "ntioctl.h"
-#include "libcli/security/secdesc.h"
+#include "libcli/security/security.h"
#include "../libcli/smb/smbXcli_base.h"
struct cli_setpathinfo_state {
@@ -1515,6 +1515,241 @@ NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const cha
return status;
}
+struct cli_smb2_hardlink_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ uint16_t fnum_src;
+ const char *fname_dst;
+ bool overwrite;
+ NTSTATUS status;
+};
+
+static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
+static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
+static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
+
+static struct tevent_req *cli_smb2_hardlink_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool overwrite,
+ struct smb2_create_blobs *in_cblobs)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_smb2_hardlink_state *state = NULL;
+
+ req = tevent_req_create(
+ mem_ctx, &state, struct cli_smb2_hardlink_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+ state->fname_dst = fname_dst;
+ state->overwrite = overwrite;
+
+ subreq = cli_smb2_create_fnum_send(
+ state,
+ ev,
+ cli,
+ fname_src,
+ 0, /* create_flags */
+ SMB2_IMPERSONATION_IMPERSONATION,
+ FILE_WRITE_ATTRIBUTES,
+ 0, /* file attributes */
+ FILE_SHARE_READ|
+ FILE_SHARE_WRITE|
+ FILE_SHARE_DELETE, /* share_access */
+ FILE_OPEN, /* create_disposition */
+ FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
+ in_cblobs);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
+ return req;
+}
+
+static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_smb2_hardlink_state *state = tevent_req_data(
+ req, struct cli_smb2_hardlink_state);
+ NTSTATUS status;
+ smb_ucs2_t *ucs2_dst;
+ size_t ucs2_len;
+ DATA_BLOB inbuf;
+ bool ok;
+
+ status = cli_smb2_create_fnum_recv(
+ subreq, &state->fnum_src, NULL, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
+ if (!ok || (ucs2_len < 2)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ /* Don't 0-terminate the name */
+ ucs2_len -= 2;
+
+ inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
+ if (tevent_req_nomem(inbuf.data, req)) {
+ return;
+ }
+
+ if (state->overwrite) {
+ SCVAL(inbuf.data, 0, 1);
+ }
+ SIVAL(inbuf.data, 16, ucs2_len);
+ memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
+ TALLOC_FREE(ucs2_dst);
+
+ subreq = cli_smb2_set_info_fnum_send(
+ state,
+ state->ev,
+ state->cli,
+ state->fnum_src,
+ 1, /* in_info_type */
+ SMB_FILE_LINK_INFORMATION - 1000, /* in_file_info_class */
+ &inbuf,
+ 0); /* in_additional_info */
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
+}
+
+static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_smb2_hardlink_state *state = tevent_req_data(
+ req, struct cli_smb2_hardlink_state);
+
+ state->status = cli_smb2_set_info_fnum_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ /* ignore error here, we need to close the file */
+
+ subreq = cli_smb2_close_fnum_send(
+ state, state->ev, state->cli, state->fnum_src);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
+}
+
+static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
+{
+ NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
+ tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
+{
+ struct cli_smb2_hardlink_state *state = tevent_req_data(
+ req, struct cli_smb2_hardlink_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return state->status;
+}
+
+struct cli_hardlink_state {
+ uint8_t dummy;
+};
+
+static void cli_hardlink_done(struct tevent_req *subreq);
+static void cli_hardlink_done2(struct tevent_req *subreq);
+
+struct tevent_req *cli_hardlink_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_hardlink_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ subreq = cli_smb2_hardlink_send(
+ state, ev, cli, fname_src, fname_dst, false, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_hardlink_done2, req);
+ return req;
+ }
+
+ subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_hardlink_done, req);
+ return req;
+}
+
+static void cli_hardlink_done(struct tevent_req *subreq)
+{
+ NTSTATUS status = cli_nt_hardlink_recv(subreq);
+ tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+static void cli_hardlink_done2(struct tevent_req *subreq)
+{
+ NTSTATUS status = cli_smb2_hardlink_recv(subreq);
+ tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+NTSTATUS cli_hardlink_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_hardlink(
+ struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_hardlink_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
/****************************************************************************
Delete a file.
****************************************************************************/
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 18d247fbe7e..a42f424df1e 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -360,6 +360,18 @@ struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req);
NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst);
+struct tevent_req *cli_hardlink_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst);
+NTSTATUS cli_hardlink_recv(struct tevent_req *req);
+NTSTATUS cli_hardlink(
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst);
+
struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,