#include "libcli/security/secdesc.h"
#include "../libcli/smb/smbXcli_base.h"
-/***********************************************************
- Common function for pushing stings, used by smb_bytes_push_str()
- and trans_bytes_push_str(). Only difference is the align_odd
- parameter setting.
-***********************************************************/
-
-static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
- const char *str, size_t str_len,
- bool align_odd,
- size_t *pconverted_size)
-{
- size_t buflen;
- char *converted;
- size_t converted_size;
-
- if (buf == NULL) {
- return NULL;
- }
-
- buflen = talloc_get_size(buf);
-
- if (ucs2 &&
- ((align_odd && (buflen % 2 == 0)) ||
- (!align_odd && (buflen % 2 == 1)))) {
- /*
- * We're pushing into an SMB buffer, align odd
- */
- buf = talloc_realloc(NULL, buf, uint8_t, buflen + 1);
- if (buf == NULL) {
- return NULL;
- }
- buf[buflen] = '\0';
- buflen += 1;
- }
-
- if (!convert_string_talloc(talloc_tos(), CH_UNIX,
- ucs2 ? CH_UTF16LE : CH_DOS,
- str, str_len, &converted,
- &converted_size)) {
- return NULL;
- }
-
- buf = talloc_realloc(NULL, buf, uint8_t,
- buflen + converted_size);
- if (buf == NULL) {
- TALLOC_FREE(converted);
- return NULL;
- }
-
- memcpy(buf + buflen, converted, converted_size);
-
- TALLOC_FREE(converted);
-
- if (pconverted_size) {
- *pconverted_size = converted_size;
- }
-
- return buf;
-}
-
-/***********************************************************
- Push a string into an SMB buffer, with odd byte alignment
- if it's a UCS2 string.
-***********************************************************/
-
-uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
- const char *str, size_t str_len,
- size_t *pconverted_size)
-{
- return internal_bytes_push_str(buf, ucs2, str, str_len,
- true, pconverted_size);
-}
-
-uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
- const uint8_t *bytes, size_t num_bytes)
-{
- size_t buflen;
-
- if (buf == NULL) {
- return NULL;
- }
- buflen = talloc_get_size(buf);
-
- buf = talloc_realloc(NULL, buf, uint8_t,
- buflen + 1 + num_bytes);
- if (buf == NULL) {
- return NULL;
- }
- buf[buflen] = prefix;
- memcpy(&buf[buflen+1], bytes, num_bytes);
- return buf;
-}
-
-/***********************************************************
- Same as smb_bytes_push_str(), but without the odd byte
- align for ucs2 (we're pushing into a param or data block).
- static for now, although this will probably change when
- other modules use async trans calls.
-***********************************************************/
-
-uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
- const char *str, size_t str_len,
- size_t *pconverted_size)
-{
- return internal_bytes_push_str(buf, ucs2, str, str_len,
- false, pconverted_size);
-}
-
-uint8_t *trans2_bytes_push_bytes(uint8_t *buf,
- const uint8_t *bytes, size_t num_bytes)
-{
- size_t buflen;
-
- if (buf == NULL) {
- return NULL;
- }
- buflen = talloc_get_size(buf);
-
- buf = talloc_realloc(NULL, buf, uint8_t,
- buflen + num_bytes);
- if (buf == NULL) {
- return NULL;
- }
- memcpy(&buf[buflen], bytes, num_bytes);
- return buf;
-}
-
struct cli_setpathinfo_state {
uint16_t setup;
uint8_t *param;
{
struct tevent_req *req, *subreq;
struct cli_setpathinfo_state *state;
+ uint16_t additional_flags2 = 0;
req = tevent_req_create(mem_ctx, &state,
struct cli_setpathinfo_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
+ !INFO_LEVEL_IS_UNIX(level)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_trans_send(
state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ additional_flags2, /* additional_flags2 */
SMBtrans2, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
}
/****************************************************************************
- Do a POSIX getfacl (UNIX extensions).
+ Do a POSIX getacl - pathname based ACL get (UNIX extensions).
****************************************************************************/
-struct getfacl_state {
+struct getacl_state {
uint32_t num_data;
uint8_t *data;
};
-static void cli_posix_getfacl_done(struct tevent_req *subreq);
+static void cli_posix_getacl_done(struct tevent_req *subreq);
-struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
+struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
const char *fname)
{
struct tevent_req *req = NULL, *subreq = NULL;
- struct getfacl_state *state = NULL;
+ struct getacl_state *state = NULL;
- req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
+ req = tevent_req_create(mem_ctx, &state, struct getacl_state);
if (req == NULL) {
return NULL;
}
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
+ tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
return req;
}
-static void cli_posix_getfacl_done(struct tevent_req *subreq)
+static void cli_posix_getacl_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
- struct getfacl_state *state = tevent_req_data(
- req, struct getfacl_state);
+ struct getacl_state *state = tevent_req_data(
+ req, struct getacl_state);
NTSTATUS status;
status = cli_qpathinfo_recv(subreq, state, &state->data,
tevent_req_done(req);
}
-NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
+NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *prb_size,
char **retbuf)
{
- struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
+ struct getacl_state *state = tevent_req_data(req, struct getacl_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
return NT_STATUS_OK;
}
-NTSTATUS cli_posix_getfacl(struct cli_state *cli,
+NTSTATUS cli_posix_getacl(struct cli_state *cli,
const char *fname,
TALLOC_CTX *mem_ctx,
size_t *prb_size,
goto fail;
}
- req = cli_posix_getfacl_send(frame,
+ req = cli_posix_getacl_send(frame,
ev,
cli,
fname);
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
- status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
+ status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/****************************************************************************
+ Do a POSIX setacl - pathname based ACL set (UNIX extensions).
+****************************************************************************/
+
+struct setacl_state {
+ uint8_t *data;
+};
+
+static void cli_posix_setacl_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ const void *data,
+ size_t num_data)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct setacl_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct setacl_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->data = talloc_memdup(state, data, num_data);
+ if (tevent_req_nomem(state->data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = cli_setpathinfo_send(state,
+ ev,
+ cli,
+ SMB_SET_POSIX_ACL,
+ fname,
+ state->data,
+ num_data);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
+ return req;
+}
+
+static void cli_posix_setacl_done(struct tevent_req *subreq)
+{
+ NTSTATUS status = cli_setpathinfo_recv(subreq);
+ tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_posix_setacl(struct cli_state *cli,
+ const char *fname,
+ const void *acl_buf,
+ size_t acl_buf_size)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = cli_posix_setacl_send(frame,
+ ev,
+ cli,
+ fname,
+ acl_buf,
+ acl_buf_size);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+
+ status = cli_posix_setacl_recv(req);
fail:
TALLOC_FREE(frame);
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
Rename a file.
****************************************************************************/
-static void cli_rename_done(struct tevent_req *subreq);
+static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace);
+
+static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace);
+
+struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace)
+{
+ if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
+ return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
+ fname_dst, replace);
+ } else {
+ return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
+ fname_dst, replace);
+ }
+}
+
+struct cli_smb1_rename_state {
+ uint8_t *data;
+};
+
+static void cli_smb1_rename_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace)
+{
+ NTSTATUS status;
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_smb1_rename_state *state = NULL;
+ smb_ucs2_t *converted_str = NULL;
+ size_t converted_size_bytes = 0;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
+ &converted_size_bytes)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ /* W2K8 insists the dest name is not null
+ terminated. Remove the last 2 zero bytes
+ and reduce the name length. */
+
+ if (converted_size_bytes < 2) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ converted_size_bytes -= 2;
+
+ state->data =
+ talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
+ if (state->data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (replace) {
+ SCVAL(state->data, 0, 1);
+ }
+
+ SIVAL(state->data, 8, converted_size_bytes);
+ memcpy(state->data + 12, converted_str, converted_size_bytes);
+
+ TALLOC_FREE(converted_str);
-struct cli_rename_state {
+ subreq = cli_setpathinfo_send(
+ state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
+ talloc_get_size(state->data));
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
+ return req;
+
+fail:
+ TALLOC_FREE(converted_str);
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+}
+
+static void cli_smb1_rename_done(struct tevent_req *subreq)
+{
+ NTSTATUS status = cli_setpathinfo_recv(subreq);
+ tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+static void cli_cifs_rename_done(struct tevent_req *subreq);
+
+struct cli_cifs_rename_state {
uint16_t vwv[1];
};
-struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct cli_state *cli,
- const char *fname_src,
- const char *fname_dst)
+static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace)
{
struct tevent_req *req = NULL, *subreq = NULL;
- struct cli_rename_state *state = NULL;
+ struct cli_cifs_rename_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
- req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
+ req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
if (req == NULL) {
return NULL;
}
+ if (replace) {
+ /*
+ * CIFS doesn't support replace
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
bytes = talloc_array(state, uint8_t, 1);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
bytes = talloc_realloc(state, bytes, uint8_t,
talloc_get_size(bytes)+1);
if (tevent_req_nomem(bytes, req)) {
}
subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
- 1, state->vwv, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 1, state->vwv, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_rename_done, req);
+ tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
return req;
}
-static void cli_rename_done(struct tevent_req *subreq)
+static void cli_cifs_rename_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
return tevent_req_simple_recv_ntstatus(req);
}
-NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+NTSTATUS cli_rename(struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace)
{
TALLOC_CTX *frame = NULL;
struct tevent_context *ev;
NTSTATUS status = NT_STATUS_OK;
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return cli_smb2_rename(cli,
- fname_src,
- fname_dst);
+ return cli_smb2_rename(cli, fname_src, fname_dst, replace);
}
frame = talloc_stackframe();
goto fail;
}
- req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
+ req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
if (req == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
struct tevent_req *req = NULL, *subreq = NULL;
struct cli_ntrename_internal_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state,
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
bytes = talloc_realloc(state, bytes, uint8_t,
talloc_get_size(bytes)+1);
if (tevent_req_nomem(bytes, req)) {
}
subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
- 4, state->vwv, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 4, state->vwv, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
struct tevent_req *req = NULL, *subreq = NULL;
struct cli_unlink_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
+ additional_flags2,
1, state->vwv, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
struct tevent_req *req = NULL, *subreq = NULL;
struct cli_mkdir_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
- 0, NULL, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 0, NULL, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
struct tevent_req *req = NULL, *subreq = NULL;
struct cli_rmdir_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
- 0, NULL, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 0, NULL, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
subreq = cli_trans_send(state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ 0, /* additional_flags2 */
SMBtrans2, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
return status;
}
-struct cli_ntcreate_state {
+struct cli_ntcreate1_state {
uint16_t vwv[24];
uint16_t fnum;
+ struct smb_create_returns cr;
+ struct tevent_req *subreq;
};
-static void cli_ntcreate_done(struct tevent_req *subreq);
+static void cli_ntcreate1_done(struct tevent_req *subreq);
+static bool cli_ntcreate1_cancel(struct tevent_req *req);
-struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct cli_state *cli,
- const char *fname,
- uint32_t CreatFlags,
- uint32_t DesiredAccess,
- uint32_t FileAttributes,
- uint32_t ShareAccess,
- uint32_t CreateDisposition,
- uint32_t CreateOptions,
- uint8_t SecurityFlags)
+static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t DesiredAccess,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint8_t SecurityFlags)
{
struct tevent_req *req, *subreq;
- struct cli_ntcreate_state *state;
+ struct cli_ntcreate1_state *state;
uint16_t *vwv;
uint8_t *bytes;
size_t converted_len;
+ uint16_t additional_flags2 = 0;
- req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
+ req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
if (req == NULL) {
return NULL;
}
fname, strlen(fname)+1,
&converted_len);
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
/* sigh. this copes with broken netapp filer behaviour */
bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
SSVAL(vwv+2, 1, converted_len);
- subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
- talloc_get_size(bytes), bytes);
+ subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
+ additional_flags2, 24, vwv,
+ talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_ntcreate_done, req);
+ tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
+
+ state->subreq = subreq;
+ tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
+
return req;
}
-static void cli_ntcreate_done(struct tevent_req *subreq)
+static void cli_ntcreate1_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
- struct cli_ntcreate_state *state = tevent_req_data(
- req, struct cli_ntcreate_state);
+ struct cli_ntcreate1_state *state = tevent_req_data(
+ req, struct cli_ntcreate1_state);
uint8_t wct;
uint16_t *vwv;
uint32_t num_bytes;
uint8_t *bytes;
NTSTATUS status;
- status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv,
+ status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
&num_bytes, &bytes);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
+ state->cr.oplock_level = CVAL(vwv+2, 0);
state->fnum = SVAL(vwv+2, 1);
+ state->cr.create_action = IVAL(vwv+3, 1);
+ state->cr.creation_time = BVAL(vwv+5, 1);
+ state->cr.last_access_time = BVAL(vwv+9, 1);
+ state->cr.last_write_time = BVAL(vwv+13, 1);
+ state->cr.change_time = BVAL(vwv+17, 1);
+ state->cr.file_attributes = IVAL(vwv+21, 1);
+ state->cr.allocation_size = BVAL(vwv+23, 1);
+ state->cr.end_of_file = BVAL(vwv+27, 1);
+
tevent_req_done(req);
}
-NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
+static bool cli_ntcreate1_cancel(struct tevent_req *req)
+{
+ struct cli_ntcreate1_state *state = tevent_req_data(
+ req, struct cli_ntcreate1_state);
+ return tevent_req_cancel(state->subreq);
+}
+
+static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
+ uint16_t *pfnum,
+ struct smb_create_returns *cr)
+{
+ struct cli_ntcreate1_state *state = tevent_req_data(
+ req, struct cli_ntcreate1_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *pfnum = state->fnum;
+ if (cr != NULL) {
+ *cr = state->cr;
+ }
+ return NT_STATUS_OK;
+}
+
+struct cli_ntcreate_state {
+ NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
+ struct smb_create_returns *cr);
+ struct smb_create_returns cr;
+ uint16_t fnum;
+ struct tevent_req *subreq;
+};
+
+static void cli_ntcreate_done(struct tevent_req *subreq);
+static bool cli_ntcreate_cancel(struct tevent_req *req);
+
+struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ uint32_t create_flags,
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint8_t security_flags)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_ntcreate_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ state->recv = cli_smb2_create_fnum_recv;
+
+ if (cli->use_oplocks) {
+ create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
+ }
+
+ subreq = cli_smb2_create_fnum_send(
+ state, ev, cli, fname, create_flags, desired_access,
+ file_attributes, share_access, create_disposition,
+ create_options);
+ } else {
+ state->recv = cli_ntcreate1_recv;
+ subreq = cli_ntcreate1_send(
+ state, ev, cli, fname, create_flags, desired_access,
+ file_attributes, share_access, create_disposition,
+ create_options, security_flags);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_ntcreate_done, req);
+
+ state->subreq = subreq;
+ tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
+
+ return req;
+}
+
+static void cli_ntcreate_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_ntcreate_state *state = tevent_req_data(
+ req, struct cli_ntcreate_state);
+ NTSTATUS status;
+
+ status = state->recv(subreq, &state->fnum, &state->cr);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static bool cli_ntcreate_cancel(struct tevent_req *req)
+{
+ struct cli_ntcreate_state *state = tevent_req_data(
+ req, struct cli_ntcreate_state);
+ return tevent_req_cancel(state->subreq);
+}
+
+NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
+ struct smb_create_returns *cr)
{
struct cli_ntcreate_state *state = tevent_req_data(
req, struct cli_ntcreate_state);
if (tevent_req_is_nterror(req, &status)) {
return status;
}
- *pfnum = state->fnum;
+ if (fnum != NULL) {
+ *fnum = state->fnum;
+ }
+ if (cr != NULL) {
+ *cr = state->cr;
+ }
return NT_STATUS_OK;
}
uint32_t CreateDisposition,
uint32_t CreateOptions,
uint8_t SecurityFlags,
- uint16_t *pfid)
+ uint16_t *pfid,
+ struct smb_create_returns *cr)
{
- TALLOC_CTX *frame = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
struct tevent_req *req;
- NTSTATUS status = NT_STATUS_OK;
-
- if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return cli_smb2_create_fnum(cli,
- fname,
- CreatFlags,
- DesiredAccess,
- FileAttributes,
- ShareAccess,
- CreateDisposition,
- CreateOptions,
- pfid,
- NULL);
- }
-
- frame = talloc_stackframe();
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
ev = samba_tevent_context_init(frame);
if (ev == NULL) {
- status = NT_STATUS_NO_MEMORY;
goto fail;
}
CreateDisposition, CreateOptions,
SecurityFlags);
if (req == NULL) {
- status = NT_STATUS_NO_MEMORY;
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
- status = cli_ntcreate_recv(req, pfid);
+ status = cli_ntcreate_recv(req, pfid, cr);
fail:
TALLOC_FREE(frame);
return status;
struct cli_nttrans_create_state {
uint16_t fnum;
+ struct smb_create_returns cr;
};
static void cli_nttrans_create_done(struct tevent_req *subreq);
size_t secdesc_len;
NTSTATUS status;
size_t converted_len;
+ uint16_t additional_flags2 = 0;
req = tevent_req_create(mem_ctx,
&state, struct cli_nttrans_create_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
SIVAL(param, 0, CreatFlags);
SIVAL(param, 4, 0x0); /* RootDirectoryFid */
SIVAL(param, 8, DesiredAccess);
SIVAL(param, 48, 0x02); /* ImpersonationLevel */
SCVAL(param, 52, SecurityFlags);
- subreq = cli_trans_send(state, ev, cli, SMBnttrans,
+ subreq = cli_trans_send(state, ev, cli,
+ additional_flags2, /* additional_flags2 */
+ SMBnttrans,
NULL, -1, /* name, fid */
NT_TRANSACT_CREATE, 0,
NULL, 0, 0, /* setup */
if (tevent_req_nterror(req, status)) {
return;
}
+ state->cr.oplock_level = CVAL(param, 0);
state->fnum = SVAL(param, 2);
+ state->cr.create_action = IVAL(param, 4);
+ state->cr.creation_time = BVAL(param, 12);
+ state->cr.last_access_time = BVAL(param, 20);
+ state->cr.last_write_time = BVAL(param, 28);
+ state->cr.change_time = BVAL(param, 36);
+ state->cr.file_attributes = IVAL(param, 44);
+ state->cr.allocation_size = BVAL(param, 48);
+ state->cr.end_of_file = BVAL(param, 56);
+
TALLOC_FREE(param);
tevent_req_done(req);
}
-NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
+NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
+ uint16_t *fnum,
+ struct smb_create_returns *cr)
{
struct cli_nttrans_create_state *state = tevent_req_data(
req, struct cli_nttrans_create_state);
return status;
}
*fnum = state->fnum;
+ if (cr != NULL) {
+ *cr = state->cr;
+ }
return NT_STATUS_OK;
}
struct security_descriptor *secdesc,
struct ea_struct *eas,
int num_eas,
- uint16_t *pfid)
+ uint16_t *pfid,
+ struct smb_create_returns *cr)
{
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
- status = cli_nttrans_create_recv(req, pfid);
+ status = cli_nttrans_create_recv(req, pfid, cr);
fail:
TALLOC_FREE(frame);
return status;
unsigned openfn;
unsigned accessmode;
uint8_t additional_flags;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes;
req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
state->bytes.iov_base = (void *)bytes;
state->bytes.iov_len = talloc_get_size(bytes);
subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
- 15, state->vwv, 1, &state->bytes);
+ additional_flags2, 15, state->vwv, 1, &state->bytes);
if (subreq == NULL) {
TALLOC_FREE(req);
return NULL;
unsigned int openfn = 0;
unsigned int dos_deny = 0;
uint32_t access_mask, share_mode, create_disposition, create_options;
+ struct smb_create_returns cr;
/* Do the initial mapping into OpenX parameters. */
if (flags & O_CREAT) {
create_disposition,
create_options,
0,
- pfnum);
+ pfnum,
+ &cr);
/* Try and cope will all varients of "we don't do this call"
and fall back to openX. */
goto try_openx;
}
+ if (NT_STATUS_IS_OK(status) &&
+ (create_options & FILE_NON_DIRECTORY_FILE) &&
+ (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ /*
+ * Some (broken) servers return a valid handle
+ * for directories even if FILE_NON_DIRECTORY_FILE
+ * is set. Just close the handle and set the
+ * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
+ */
+ status = cli_close(cli, *pfnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = NT_STATUS_FILE_IS_A_DIRECTORY;
+ /* Set this so libsmbclient can retrieve it. */
+ cli->raw_status = status;
+ }
+
return status;
try_openx:
SSVAL(state->vwv+0, 0, fnum);
SIVALS(state->vwv+1, 0, -1);
- subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
- 0, NULL);
+ subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
+ 3, state->vwv, 0, NULL);
if (subreq == NULL) {
TALLOC_FREE(req);
return NULL;
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
subreq = cli_trans_send(state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ 0, /* additional_flags2 */
SMBtrans2, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
{
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
struct tevent_context *ev = NULL;
struct tevent_req *req = NULL;
NTSTATUS status = NT_STATUS_OK;
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_ftruncate(cli, fnum, size);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
SIVAL(state->data, 2, offset);
SIVAL(state->data, 6, len);
- subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
+ subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
8, state->vwv, 10, state->data);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
SOFF_T_R(state->data, 4, offset);
SOFF_T_R(state->data, 12, len);
- subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
+ subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
8, state->vwv, 20, state->data);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
subreq = cli_trans_send(state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ 0, /* additional_flags2 */
SMBtrans2, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
SSVAL(state->vwv+0,0,fnum);
- subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
+ subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
1, state->vwv, 0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
struct tevent_req *req = NULL, *subreq = NULL;
struct cli_getatr_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
- 0, NULL, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 0, NULL, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
smb1cli_conn_server_time_zone(cli->conn));
- subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
+ subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
7, state->vwv, 0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
struct tevent_req *req = NULL, *subreq = NULL;
struct cli_setatr_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
- 8, state->vwv, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 8, state->vwv, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
}
/****************************************************************************
- Check for existance of a dir.
+ Check for existence of a dir.
****************************************************************************/
static void cli_chkpath_done(struct tevent_req *subreq);
struct tevent_req *req = NULL, *subreq = NULL;
struct cli_chkpath_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
- 0, NULL, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 0, NULL, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
return NULL;
}
- subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
+ subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
0, NULL, 0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
struct tevent_req *req = NULL;
NTSTATUS status = NT_STATUS_OK;
- if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return cli_smb2_dskattr(cli, bsize, total, avail);
- }
-
frame = talloc_stackframe();
if (smbXcli_conn_has_async_calls(cli->conn)) {
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
return status;
}
+NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
+ uint64_t *total, uint64_t *avail)
+{
+ uint64_t sectors_per_block;
+ uint64_t bytes_per_sector;
+ int old_bsize, old_total, old_avail;
+ NTSTATUS status;
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_dskattr(cli, path, bsize, total, avail);
+ }
+
+ /*
+ * Try the trans2 disk full size info call first.
+ * We already use this in SMBC_fstatvfs_ctx().
+ * Ignore 'actual_available_units' as we only
+ * care about the quota for the caller.
+ */
+
+ status = cli_get_fs_full_size_info(cli,
+ total,
+ avail,
+ NULL,
+ §ors_per_block,
+ &bytes_per_sector);
+
+ /* Try and cope will all varients of "we don't do this call"
+ and fall back to cli_dskattr. */
+
+ if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
+ goto try_dskattr;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (bsize) {
+ *bsize = sectors_per_block *
+ bytes_per_sector;
+ }
+
+ return NT_STATUS_OK;
+
+ try_dskattr:
+
+ /* Old SMB1 core protocol fallback. */
+ status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (bsize) {
+ *bsize = (uint64_t)old_bsize;
+ }
+ if (total) {
+ *total = (uint64_t)old_total;
+ }
+ if (avail) {
+ *avail = (uint64_t)old_avail;
+ }
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
Create and open a temporary file.
****************************************************************************/
struct tevent_req *req = NULL, *subreq = NULL;
struct ctemp_state *state = NULL;
uint8_t additional_flags = 0;
+ uint16_t additional_flags2 = 0;
uint8_t *bytes = NULL;
req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
- 3, state->vwv, talloc_get_size(bytes), bytes);
+ additional_flags2,
+ 3, state->vwv, talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
memcpy(p+4+ea_namelen+1, ea_val, ea_len);
}
+ /*
+ * FIXME - if we want to do previous version path
+ * processing on an EA set call we need to turn this
+ * into calls to cli_trans_send()/cli_trans_recv()
+ * with a temporary event context, as cli_trans_send()
+ * have access to the additional_flags2 needed to
+ * send @GMT- paths. JRA.
+ */
+
status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
setup, 1, 0,
param, param_len, 2,
- data, data_len, CLI_BUFFER_SIZE,
+ data, data_len, 0,
NULL,
NULL, 0, NULL, /* rsetup */
NULL, 0, NULL, /* rparam */
unsigned int param_len = 0;
uint8_t *param;
NTSTATUS status;
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_set_ea_path(cli,
+ path,
+ ea_name,
+ ea_val,
+ ea_len);
+ }
+
+ frame = talloc_stackframe();
param = talloc_array(frame, uint8_t, 6);
if (!param) {
{
uint8_t param[6];
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_set_ea_fnum(cli,
+ fnum,
+ ea_name,
+ ea_val,
+ ea_len);
+ }
+
memset(param, 0, 6);
SSVAL(param,0,fnum);
SSVAL(param,2,SMB_INFO_SET_EA);
size_t *pnum_eas,
struct ea_struct **pea_list)
{
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
struct tevent_context *ev = NULL;
struct tevent_req *req = NULL;
NTSTATUS status = NT_STATUS_NO_MEMORY;
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_get_ea_list_path(cli,
+ path,
+ ctx,
+ pnum_eas,
+ pea_list);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
subreq = cli_trans_send(state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ 0, /* additional_flags2 */
SMBtrans2, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ 0, /* additional_flags2 */
SMBnttrans, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
{
struct tevent_req *req, *subreq;
struct cli_qpathinfo_state *state;
+ uint16_t additional_flags2 = 0;
req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
if (req == NULL) {
return tevent_req_post(req, ev);
}
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
+ !INFO_LEVEL_IS_UNIX(level)) {
+ additional_flags2 = FLAGS2_REPARSE_PATH;
+ }
+
subreq = cli_trans_send(
state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ additional_flags2, /* additional_flags2 */
SMBtrans2, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
state, /* mem ctx. */
ev, /* event ctx. */
cli, /* cli_state. */
+ 0, /* additional_flags2 */
SMBtrans2, /* cmd. */
NULL, /* pipe name. */
-1, /* fid. */
}
SSVAL(state->vwv + 0, 0, fnum);
- subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
+ subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
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,
+ state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
+ state->setup, ARRAY_SIZE(state->setup),
+ ARRAY_SIZE(state->setup),
NULL, 0, 0,
NULL, 0, ret_size);
if (tevent_req_nomem(subreq, req)) {
{
struct cli_shadow_copy_data_state *state = tevent_req_data(
req, struct cli_shadow_copy_data_state);
- char **names;
- int i, num_names;
+ char **names = NULL;
+ uint32_t i, num_names;
uint32_t dlength;
+ uint8_t *endp = NULL;
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
return status;
}
+
+ if (state->num_data < 16) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
num_names = IVAL(state->data, 4);
dlength = IVAL(state->data, 8);
+ if (num_names > 0x7FFFFFFF) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
if (!state->get_names) {
- *pnum_names = num_names;
+ *pnum_names = (int)num_names;
return NT_STATUS_OK;
}
- if (dlength+12 > state->num_data) {
+ if (dlength + 12 < 12) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (dlength + 12 > state->num_data) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
+ 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;
}
+ endp = state->data + state->num_data;
+
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);
+
+ if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
ret = convert_string_talloc(
names, CH_UTF16LE, CH_UNIX,
src, 2 * sizeof(SHADOW_COPY_LABEL),
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
}
- *pnum_names = num_names;
+ *pnum_names = (int)num_names;
*pnames = names;
return NT_STATUS_OK;
}
uint16_t fnum, bool get_names,
char ***pnames, int *pnum_names)
{
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
struct tevent_context *ev;
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_shadow_copy_data(mem_ctx,
+ cli,
+ fnum,
+ get_names,
+ pnames,
+ pnum_names);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight