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;
- 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;
}
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);
+}
+
+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);
}
-NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
+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);
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 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:
NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
{
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
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_close_fnum(cli, fnum);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
time_t *access_time,
time_t *write_time)
{
- 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_getattrE(cli,
+ fnum,
+ attr,
+ size,
+ change_time,
+ access_time,
+ write_time);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
off_t *size,
time_t *write_time)
{
- 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_getatr(cli,
+ fname,
+ attr,
+ size,
+ write_time);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
time_t access_time,
time_t write_time)
{
- 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_setattrE(cli,
+ fnum,
+ change_time,
+ access_time,
+ write_time);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
uint16_t attr,
time_t mtime)
{
- 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_setatr(cli,
+ fname,
+ attr,
+ mtime);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
{
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
struct tevent_context *ev = NULL;
struct tevent_req *req = NULL;
NTSTATUS status = NT_STATUS_OK;
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
return status;
}
+NTSTATUS cli_disk_size(struct cli_state *cli, 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, 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.
****************************************************************************/
unsigned int param_len = 0;
uint8_t *param;
NTSTATUS status;
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
- param = talloc_array(talloc_tos(), uint8_t, 6);
+ 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) {
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
SSVAL(param,0,SMB_INFO_SET_EA);
SSVAL(param,2,0);
status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
ea_name, ea_val, ea_len);
- talloc_free(frame);
+
+ fail:
+
+ TALLOC_FREE(frame);
return status;
}
{
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