1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-27 14:04:05 +03:00

libsmb: Introduce protocol-agnostic cli_hardlink

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Volker Lendecke 2019-03-18 10:34:53 +01:00 committed by Jeremy Allison
parent b4c87b09b6
commit b5af004b23
2 changed files with 248 additions and 1 deletions

View File

@ -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.
****************************************************************************/

View File

@ -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,