mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
69e24b4e8b
Add a return parameter of struct smb_create_returns *cr to cli_ntcreate() cli_ntcreate_recv() cli_nttrans_create() cli_nttrans_create_recv() Always pass in NULL for now. This fixes the create API to always fully return the data the server has given back to us on the open file to the caller. Signed-off-by: Jeremy Allison <jra@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
501 lines
12 KiB
C
501 lines
12 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
In-memory cache
|
|
Copyright (C) Volker Lendecke 2007
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "torture/proto.h"
|
|
#include "libsmb/libsmb.h"
|
|
#include "libsmb/clirap.h"
|
|
#include "../lib/util/tevent_ntstatus.h"
|
|
|
|
static long long int ival(const char *str)
|
|
{
|
|
return strtoll(str, NULL, 0);
|
|
}
|
|
|
|
struct nbench_state {
|
|
struct tevent_context *ev;
|
|
struct cli_state *cli;
|
|
const char *cliname;
|
|
FILE *loadfile;
|
|
struct ftable *ftable;
|
|
void (*bw_report)(size_t nread,
|
|
size_t nwritten,
|
|
void *private_data);
|
|
void *bw_report_private;
|
|
};
|
|
|
|
struct lock_info {
|
|
struct lock_info *next, *prev;
|
|
off_t offset;
|
|
int size;
|
|
};
|
|
|
|
struct createx_params {
|
|
char *fname;
|
|
unsigned int cr_options;
|
|
unsigned int cr_disposition;
|
|
int handle;
|
|
};
|
|
|
|
struct ftable {
|
|
struct ftable *next, *prev;
|
|
struct createx_params cp;
|
|
struct lock_info *locks;
|
|
uint16_t fnum; /* the fd that we got back from the server */
|
|
};
|
|
|
|
enum nbench_cmd {
|
|
NBENCH_CMD_NTCREATEX,
|
|
NBENCH_CMD_CLOSE,
|
|
NBENCH_CMD_RENAME,
|
|
NBENCH_CMD_UNLINK,
|
|
NBENCH_CMD_DELTREE,
|
|
NBENCH_CMD_RMDIR,
|
|
NBENCH_CMD_MKDIR,
|
|
NBENCH_CMD_QUERY_PATH_INFORMATION,
|
|
NBENCH_CMD_QUERY_FILE_INFORMATION,
|
|
NBENCH_CMD_QUERY_FS_INFORMATION,
|
|
NBENCH_CMD_SET_FILE_INFORMATION,
|
|
NBENCH_CMD_FIND_FIRST,
|
|
NBENCH_CMD_WRITEX,
|
|
NBENCH_CMD_WRITE,
|
|
NBENCH_CMD_LOCKX,
|
|
NBENCH_CMD_UNLOCKX,
|
|
NBENCH_CMD_READX,
|
|
NBENCH_CMD_FLUSH,
|
|
NBENCH_CMD_SLEEP,
|
|
};
|
|
|
|
struct nbench_cmd_struct {
|
|
char **params;
|
|
int num_params;
|
|
NTSTATUS status;
|
|
enum nbench_cmd cmd;
|
|
};
|
|
|
|
static struct nbench_cmd_struct *nbench_parse(TALLOC_CTX *mem_ctx,
|
|
const char *line)
|
|
{
|
|
struct nbench_cmd_struct *result;
|
|
char *cmd;
|
|
char *status;
|
|
|
|
result = talloc(mem_ctx, struct nbench_cmd_struct);
|
|
if (result == NULL) {
|
|
return NULL;
|
|
}
|
|
result->params = str_list_make_shell(mem_ctx, line, " ");
|
|
if (result->params == NULL) {
|
|
goto fail;
|
|
}
|
|
result->num_params = talloc_array_length(result->params) - 1;
|
|
if (result->num_params < 2) {
|
|
goto fail;
|
|
}
|
|
status = result->params[result->num_params-1];
|
|
if (strncmp(status, "NT_STATUS_", 10) != 0 &&
|
|
strncmp(status, "0x", 2) != 0) {
|
|
goto fail;
|
|
}
|
|
/* accept numeric or string status codes */
|
|
if (strncmp(status, "0x", 2) == 0) {
|
|
result->status = NT_STATUS(strtoul(status, NULL, 16));
|
|
} else {
|
|
result->status = nt_status_string_to_code(status);
|
|
}
|
|
|
|
cmd = result->params[0];
|
|
|
|
if (!strcmp(cmd, "NTCreateX")) {
|
|
result->cmd = NBENCH_CMD_NTCREATEX;
|
|
} else if (!strcmp(cmd, "Close")) {
|
|
result->cmd = NBENCH_CMD_CLOSE;
|
|
} else if (!strcmp(cmd, "Rename")) {
|
|
result->cmd = NBENCH_CMD_RENAME;
|
|
} else if (!strcmp(cmd, "Unlink")) {
|
|
result->cmd = NBENCH_CMD_UNLINK;
|
|
} else if (!strcmp(cmd, "Deltree")) {
|
|
result->cmd = NBENCH_CMD_DELTREE;
|
|
} else if (!strcmp(cmd, "Rmdir")) {
|
|
result->cmd = NBENCH_CMD_RMDIR;
|
|
} else if (!strcmp(cmd, "Mkdir")) {
|
|
result->cmd = NBENCH_CMD_MKDIR;
|
|
} else if (!strcmp(cmd, "QUERY_PATH_INFORMATION")) {
|
|
result->cmd = NBENCH_CMD_QUERY_PATH_INFORMATION;
|
|
} else if (!strcmp(cmd, "QUERY_FILE_INFORMATION")) {
|
|
result->cmd = NBENCH_CMD_QUERY_FILE_INFORMATION;
|
|
} else if (!strcmp(cmd, "QUERY_FS_INFORMATION")) {
|
|
result->cmd = NBENCH_CMD_QUERY_FS_INFORMATION;
|
|
} else if (!strcmp(cmd, "SET_FILE_INFORMATION")) {
|
|
result->cmd = NBENCH_CMD_SET_FILE_INFORMATION;
|
|
} else if (!strcmp(cmd, "FIND_FIRST")) {
|
|
result->cmd = NBENCH_CMD_FIND_FIRST;
|
|
} else if (!strcmp(cmd, "WriteX")) {
|
|
result->cmd = NBENCH_CMD_WRITEX;
|
|
} else if (!strcmp(cmd, "Write")) {
|
|
result->cmd = NBENCH_CMD_WRITE;
|
|
} else if (!strcmp(cmd, "LockX")) {
|
|
result->cmd = NBENCH_CMD_LOCKX;
|
|
} else if (!strcmp(cmd, "UnlockX")) {
|
|
result->cmd = NBENCH_CMD_UNLOCKX;
|
|
} else if (!strcmp(cmd, "ReadX")) {
|
|
result->cmd = NBENCH_CMD_READX;
|
|
} else if (!strcmp(cmd, "Flush")) {
|
|
result->cmd = NBENCH_CMD_FLUSH;
|
|
} else if (!strcmp(cmd, "Sleep")) {
|
|
result->cmd = NBENCH_CMD_SLEEP;
|
|
} else {
|
|
goto fail;
|
|
}
|
|
return result;
|
|
fail:
|
|
TALLOC_FREE(result);
|
|
return NULL;
|
|
}
|
|
|
|
static struct ftable *ft_find(struct ftable *ftlist, int handle)
|
|
{
|
|
while (ftlist != NULL) {
|
|
if (ftlist->cp.handle == handle) {
|
|
return ftlist;
|
|
}
|
|
ftlist = ftlist->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct nbench_cmd_state {
|
|
struct tevent_context *ev;
|
|
struct nbench_state *state;
|
|
struct nbench_cmd_struct *cmd;
|
|
struct ftable *ft;
|
|
bool eof;
|
|
};
|
|
|
|
static void nbench_cmd_done(struct tevent_req *subreq);
|
|
|
|
static struct tevent_req *nbench_cmd_send(TALLOC_CTX *mem_ctx,
|
|
struct tevent_context *ev,
|
|
struct nbench_state *nb_state)
|
|
{
|
|
struct tevent_req *req, *subreq;
|
|
struct nbench_cmd_state *state;
|
|
char line[1024];
|
|
size_t len;
|
|
|
|
req = tevent_req_create(mem_ctx, &state, struct nbench_cmd_state);
|
|
if (req == NULL) {
|
|
return NULL;
|
|
}
|
|
state->ev = ev;
|
|
state->state = nb_state;
|
|
|
|
if (fgets(line, sizeof(line), nb_state->loadfile) == NULL) {
|
|
tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
len = strlen(line);
|
|
if (len == 0) {
|
|
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
if (line[len-1] == '\n') {
|
|
line[len-1] = '\0';
|
|
}
|
|
|
|
state->cmd = nbench_parse(state, line);
|
|
if (state->cmd == NULL) {
|
|
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
|
|
switch (state->cmd->cmd) {
|
|
case NBENCH_CMD_NTCREATEX: {
|
|
uint32_t desired_access;
|
|
uint32_t share_mode;
|
|
unsigned int flags = 0;
|
|
|
|
state->ft = talloc(state, struct ftable);
|
|
if (tevent_req_nomem(state->ft, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
|
|
state->ft->cp.fname = talloc_all_string_sub(
|
|
state->ft, state->cmd->params[1], "client1",
|
|
nb_state->cliname);
|
|
if (tevent_req_nomem(state->ft->cp.fname, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
state->ft->cp.cr_options = ival(state->cmd->params[2]);
|
|
state->ft->cp.cr_disposition = ival(state->cmd->params[3]);
|
|
state->ft->cp.handle = ival(state->cmd->params[4]);
|
|
|
|
if (state->ft->cp.cr_options & FILE_DIRECTORY_FILE) {
|
|
desired_access = SEC_FILE_READ_DATA;
|
|
} else {
|
|
desired_access =
|
|
SEC_FILE_READ_DATA |
|
|
SEC_FILE_WRITE_DATA |
|
|
SEC_FILE_READ_ATTRIBUTE |
|
|
SEC_FILE_WRITE_ATTRIBUTE;
|
|
flags = EXTENDED_RESPONSE_REQUIRED
|
|
| REQUEST_OPLOCK | REQUEST_BATCH_OPLOCK;
|
|
}
|
|
share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
|
|
subreq = cli_ntcreate_send(
|
|
state, ev, nb_state->cli, state->ft->cp.fname, flags,
|
|
desired_access, 0, share_mode,
|
|
state->ft->cp.cr_disposition,
|
|
state->ft->cp.cr_options, 0);
|
|
break;
|
|
}
|
|
case NBENCH_CMD_CLOSE: {
|
|
state->ft = ft_find(state->state->ftable,
|
|
ival(state->cmd->params[1]));
|
|
if (state->ft == NULL) {
|
|
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
subreq = cli_close_send(
|
|
state, ev, nb_state->cli, state->ft->fnum);
|
|
break;
|
|
}
|
|
case NBENCH_CMD_MKDIR: {
|
|
char *fname;
|
|
fname = talloc_all_string_sub(
|
|
state, state->cmd->params[1], "client1",
|
|
nb_state->cliname);
|
|
if (tevent_req_nomem(state->ft->cp.fname, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
subreq = cli_mkdir_send(state, ev, nb_state->cli, fname);
|
|
break;
|
|
}
|
|
case NBENCH_CMD_QUERY_PATH_INFORMATION: {
|
|
char *fname;
|
|
fname = talloc_all_string_sub(
|
|
state, state->cmd->params[1], "client1",
|
|
nb_state->cliname);
|
|
if (tevent_req_nomem(state->ft->cp.fname, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
subreq = cli_qpathinfo_send(state, ev, nb_state->cli, fname,
|
|
ival(state->cmd->params[2]),
|
|
0, CLI_BUFFER_SIZE);
|
|
break;
|
|
}
|
|
default:
|
|
tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
|
|
if (tevent_req_nomem(subreq, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
tevent_req_set_callback(subreq, nbench_cmd_done, req);
|
|
return req;
|
|
}
|
|
|
|
static bool status_wrong(struct tevent_req *req, NTSTATUS expected,
|
|
NTSTATUS status)
|
|
{
|
|
if (NT_STATUS_EQUAL(expected, status)) {
|
|
return false;
|
|
}
|
|
if (NT_STATUS_IS_OK(status)) {
|
|
status = NT_STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
tevent_req_nterror(req, status);
|
|
return true;
|
|
}
|
|
|
|
static void nbench_cmd_done(struct tevent_req *subreq)
|
|
{
|
|
struct tevent_req *req = tevent_req_callback_data(
|
|
subreq, struct tevent_req);
|
|
struct nbench_cmd_state *state = tevent_req_data(
|
|
req, struct nbench_cmd_state);
|
|
struct nbench_state *nbstate = state->state;
|
|
NTSTATUS status;
|
|
|
|
switch (state->cmd->cmd) {
|
|
case NBENCH_CMD_NTCREATEX: {
|
|
struct ftable *ft;
|
|
status = cli_ntcreate_recv(subreq, &state->ft->fnum, NULL);
|
|
TALLOC_FREE(subreq);
|
|
if (status_wrong(req, state->cmd->status, status)) {
|
|
return;
|
|
}
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
tevent_req_done(req);
|
|
return;
|
|
}
|
|
ft = talloc_move(nbstate, &state->ft);
|
|
DLIST_ADD(nbstate->ftable, ft);
|
|
break;
|
|
}
|
|
case NBENCH_CMD_CLOSE: {
|
|
status = cli_close_recv(subreq);
|
|
TALLOC_FREE(subreq);
|
|
if (status_wrong(req, state->cmd->status, status)) {
|
|
return;
|
|
}
|
|
DLIST_REMOVE(state->state->ftable, state->ft);
|
|
TALLOC_FREE(state->ft);
|
|
break;
|
|
}
|
|
case NBENCH_CMD_MKDIR: {
|
|
status = cli_mkdir_recv(subreq);
|
|
TALLOC_FREE(subreq);
|
|
if (status_wrong(req, state->cmd->status, status)) {
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case NBENCH_CMD_QUERY_PATH_INFORMATION: {
|
|
status = cli_qpathinfo_recv(subreq, NULL, NULL, NULL);
|
|
TALLOC_FREE(subreq);
|
|
if (status_wrong(req, state->cmd->status, status)) {
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
tevent_req_done(req);
|
|
}
|
|
|
|
static NTSTATUS nbench_cmd_recv(struct tevent_req *req)
|
|
{
|
|
return tevent_req_simple_recv_ntstatus(req);
|
|
}
|
|
|
|
static void nbench_done(struct tevent_req *subreq);
|
|
|
|
static struct tevent_req *nbench_send(
|
|
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
|
|
const char *cliname, FILE *loadfile,
|
|
void (*bw_report)(size_t nread, size_t nwritten, void *private_data),
|
|
void *bw_report_private)
|
|
{
|
|
struct tevent_req *req, *subreq;
|
|
struct nbench_state *state;
|
|
|
|
req = tevent_req_create(mem_ctx, &state, struct nbench_state);
|
|
if (req == NULL) {
|
|
return NULL;
|
|
}
|
|
state->ev = ev;
|
|
state->cli = cli;
|
|
state->cliname = cliname;
|
|
state->loadfile = loadfile;
|
|
state->bw_report = bw_report;
|
|
state->bw_report_private = bw_report_private;
|
|
|
|
subreq = nbench_cmd_send(state, ev, state);
|
|
if (tevent_req_nomem(subreq, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
tevent_req_set_callback(subreq, nbench_done, req);
|
|
return req;
|
|
}
|
|
|
|
static void nbench_done(struct tevent_req *subreq)
|
|
{
|
|
struct tevent_req *req = tevent_req_callback_data(
|
|
subreq, struct tevent_req);
|
|
struct nbench_state *state = tevent_req_data(
|
|
req, struct nbench_state);
|
|
NTSTATUS status;
|
|
|
|
status = nbench_cmd_recv(subreq);
|
|
TALLOC_FREE(subreq);
|
|
|
|
if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
|
|
tevent_req_done(req);
|
|
return;
|
|
}
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
tevent_req_nterror(req, status);
|
|
return;
|
|
}
|
|
subreq = nbench_cmd_send(state, state->ev, state);
|
|
if (tevent_req_nomem(subreq, req)) {
|
|
return;
|
|
}
|
|
tevent_req_set_callback(subreq, nbench_done, req);
|
|
}
|
|
|
|
static NTSTATUS nbench_recv(struct tevent_req *req)
|
|
{
|
|
return tevent_req_simple_recv_ntstatus(req);
|
|
}
|
|
|
|
bool run_nbench2(int dummy)
|
|
{
|
|
TALLOC_CTX *frame = talloc_stackframe();
|
|
struct tevent_context *ev;
|
|
struct cli_state *cli = NULL;
|
|
FILE *loadfile;
|
|
bool ret = false;
|
|
struct tevent_req *req;
|
|
NTSTATUS status;
|
|
|
|
loadfile = fopen("client.txt", "r");
|
|
if (loadfile == NULL) {
|
|
fprintf(stderr, "Could not open \"client.txt\": %s\n",
|
|
strerror(errno));
|
|
return false;
|
|
}
|
|
ev = samba_tevent_context_init(talloc_tos());
|
|
if (ev == NULL) {
|
|
goto fail;
|
|
}
|
|
if (!torture_open_connection(&cli, 0)) {
|
|
goto fail;
|
|
}
|
|
|
|
req = nbench_send(talloc_tos(), ev, cli, "client1", loadfile,
|
|
NULL, NULL);
|
|
if (req == NULL) {
|
|
goto fail;
|
|
}
|
|
if (!tevent_req_poll(req, ev)) {
|
|
goto fail;
|
|
}
|
|
status = nbench_recv(req);
|
|
TALLOC_FREE(req);
|
|
printf("nbench returned %s\n", nt_errstr(status));
|
|
|
|
ret = true;
|
|
fail:
|
|
if (cli != NULL) {
|
|
torture_close_connection(cli);
|
|
}
|
|
TALLOC_FREE(ev);
|
|
if (loadfile != NULL) {
|
|
fclose(loadfile);
|
|
loadfile = NULL;
|
|
}
|
|
TALLOC_FREE(frame);
|
|
return ret;
|
|
}
|