smbd: Slightly simplify create_file_unixpath()
[Samba.git] / source3 / torture / nbench.c
blobe9a0b4f2f33f8176dd3c56963ea622876d34f2c3
1 /*
2 Unix SMB/CIFS implementation.
3 In-memory cache
4 Copyright (C) Volker Lendecke 2007
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "torture/proto.h"
22 #include "libsmb/libsmb.h"
23 #include "libsmb/clirap.h"
24 #include "../lib/util/tevent_ntstatus.h"
26 static long long int ival(const char *str)
28 return strtoll(str, NULL, 0);
31 struct nbench_state {
32 struct tevent_context *ev;
33 struct cli_state *cli;
34 const char *cliname;
35 FILE *loadfile;
36 struct ftable *ftable;
37 void (*bw_report)(size_t nread,
38 size_t nwritten,
39 void *private_data);
40 void *bw_report_private;
43 struct lock_info {
44 struct lock_info *next, *prev;
45 off_t offset;
46 int size;
49 struct createx_params {
50 char *fname;
51 unsigned int cr_options;
52 unsigned int cr_disposition;
53 int handle;
56 struct ftable {
57 struct ftable *next, *prev;
58 struct createx_params cp;
59 struct lock_info *locks;
60 uint16_t fnum; /* the fd that we got back from the server */
63 enum nbench_cmd {
64 NBENCH_CMD_NTCREATEX,
65 NBENCH_CMD_CLOSE,
66 NBENCH_CMD_RENAME,
67 NBENCH_CMD_UNLINK,
68 NBENCH_CMD_DELTREE,
69 NBENCH_CMD_RMDIR,
70 NBENCH_CMD_MKDIR,
71 NBENCH_CMD_QUERY_PATH_INFORMATION,
72 NBENCH_CMD_QUERY_FILE_INFORMATION,
73 NBENCH_CMD_QUERY_FS_INFORMATION,
74 NBENCH_CMD_SET_FILE_INFORMATION,
75 NBENCH_CMD_FIND_FIRST,
76 NBENCH_CMD_WRITEX,
77 NBENCH_CMD_WRITE,
78 NBENCH_CMD_LOCKX,
79 NBENCH_CMD_UNLOCKX,
80 NBENCH_CMD_READX,
81 NBENCH_CMD_FLUSH,
82 NBENCH_CMD_SLEEP,
85 struct nbench_cmd_struct {
86 char **params;
87 int num_params;
88 NTSTATUS status;
89 enum nbench_cmd cmd;
92 static struct nbench_cmd_struct *nbench_parse(TALLOC_CTX *mem_ctx,
93 const char *line)
95 struct nbench_cmd_struct *result;
96 char *cmd;
97 char *status;
99 result = talloc(mem_ctx, struct nbench_cmd_struct);
100 if (result == NULL) {
101 return NULL;
103 result->params = str_list_make_shell(mem_ctx, line, " ");
104 if (result->params == NULL) {
105 goto fail;
107 result->num_params = talloc_array_length(result->params) - 1;
108 if (result->num_params < 2) {
109 goto fail;
111 status = result->params[result->num_params-1];
112 if (strncmp(status, "NT_STATUS_", 10) != 0 &&
113 strncmp(status, "0x", 2) != 0) {
114 goto fail;
116 /* accept numeric or string status codes */
117 if (strncmp(status, "0x", 2) == 0) {
118 result->status = NT_STATUS(strtoul(status, NULL, 16));
119 } else {
120 result->status = nt_status_string_to_code(status);
123 cmd = result->params[0];
125 if (!strcmp(cmd, "NTCreateX")) {
126 result->cmd = NBENCH_CMD_NTCREATEX;
127 } else if (!strcmp(cmd, "Close")) {
128 result->cmd = NBENCH_CMD_CLOSE;
129 } else if (!strcmp(cmd, "Rename")) {
130 result->cmd = NBENCH_CMD_RENAME;
131 } else if (!strcmp(cmd, "Unlink")) {
132 result->cmd = NBENCH_CMD_UNLINK;
133 } else if (!strcmp(cmd, "Deltree")) {
134 result->cmd = NBENCH_CMD_DELTREE;
135 } else if (!strcmp(cmd, "Rmdir")) {
136 result->cmd = NBENCH_CMD_RMDIR;
137 } else if (!strcmp(cmd, "Mkdir")) {
138 result->cmd = NBENCH_CMD_MKDIR;
139 } else if (!strcmp(cmd, "QUERY_PATH_INFORMATION")) {
140 result->cmd = NBENCH_CMD_QUERY_PATH_INFORMATION;
141 } else if (!strcmp(cmd, "QUERY_FILE_INFORMATION")) {
142 result->cmd = NBENCH_CMD_QUERY_FILE_INFORMATION;
143 } else if (!strcmp(cmd, "QUERY_FS_INFORMATION")) {
144 result->cmd = NBENCH_CMD_QUERY_FS_INFORMATION;
145 } else if (!strcmp(cmd, "SET_FILE_INFORMATION")) {
146 result->cmd = NBENCH_CMD_SET_FILE_INFORMATION;
147 } else if (!strcmp(cmd, "FIND_FIRST")) {
148 result->cmd = NBENCH_CMD_FIND_FIRST;
149 } else if (!strcmp(cmd, "WriteX")) {
150 result->cmd = NBENCH_CMD_WRITEX;
151 } else if (!strcmp(cmd, "Write")) {
152 result->cmd = NBENCH_CMD_WRITE;
153 } else if (!strcmp(cmd, "LockX")) {
154 result->cmd = NBENCH_CMD_LOCKX;
155 } else if (!strcmp(cmd, "UnlockX")) {
156 result->cmd = NBENCH_CMD_UNLOCKX;
157 } else if (!strcmp(cmd, "ReadX")) {
158 result->cmd = NBENCH_CMD_READX;
159 } else if (!strcmp(cmd, "Flush")) {
160 result->cmd = NBENCH_CMD_FLUSH;
161 } else if (!strcmp(cmd, "Sleep")) {
162 result->cmd = NBENCH_CMD_SLEEP;
163 } else {
164 goto fail;
166 return result;
167 fail:
168 TALLOC_FREE(result);
169 return NULL;
172 static struct ftable *ft_find(struct ftable *ftlist, int handle)
174 while (ftlist != NULL) {
175 if (ftlist->cp.handle == handle) {
176 return ftlist;
178 ftlist = ftlist->next;
180 return NULL;
183 struct nbench_cmd_state {
184 struct tevent_context *ev;
185 struct nbench_state *state;
186 struct nbench_cmd_struct *cmd;
187 struct ftable *ft;
188 bool eof;
191 static void nbench_cmd_done(struct tevent_req *subreq);
193 static struct tevent_req *nbench_cmd_send(TALLOC_CTX *mem_ctx,
194 struct tevent_context *ev,
195 struct nbench_state *nb_state)
197 struct tevent_req *req, *subreq;
198 struct nbench_cmd_state *state;
199 char line[1024];
200 size_t len;
202 req = tevent_req_create(mem_ctx, &state, struct nbench_cmd_state);
203 if (req == NULL) {
204 return NULL;
206 state->ev = ev;
207 state->state = nb_state;
209 if (fgets(line, sizeof(line), nb_state->loadfile) == NULL) {
210 tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
211 return tevent_req_post(req, ev);
213 len = strlen(line);
214 if (len == 0) {
215 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
216 return tevent_req_post(req, ev);
218 if (line[len-1] == '\n') {
219 line[len-1] = '\0';
222 state->cmd = nbench_parse(state, line);
223 if (state->cmd == NULL) {
224 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
225 return tevent_req_post(req, ev);
228 switch (state->cmd->cmd) {
229 case NBENCH_CMD_NTCREATEX: {
230 uint32_t desired_access;
231 uint32_t share_mode;
232 unsigned int flags = 0;
234 state->ft = talloc(state, struct ftable);
235 if (tevent_req_nomem(state->ft, req)) {
236 return tevent_req_post(req, ev);
239 state->ft->cp.fname = talloc_all_string_sub(
240 state->ft, state->cmd->params[1], "client1",
241 nb_state->cliname);
242 if (tevent_req_nomem(state->ft->cp.fname, req)) {
243 return tevent_req_post(req, ev);
245 state->ft->cp.cr_options = ival(state->cmd->params[2]);
246 state->ft->cp.cr_disposition = ival(state->cmd->params[3]);
247 state->ft->cp.handle = ival(state->cmd->params[4]);
249 if (state->ft->cp.cr_options & FILE_DIRECTORY_FILE) {
250 desired_access = SEC_FILE_READ_DATA;
251 } else {
252 desired_access =
253 SEC_FILE_READ_DATA |
254 SEC_FILE_WRITE_DATA |
255 SEC_FILE_READ_ATTRIBUTE |
256 SEC_FILE_WRITE_ATTRIBUTE;
257 flags = EXTENDED_RESPONSE_REQUIRED
258 | REQUEST_OPLOCK | REQUEST_BATCH_OPLOCK;
260 share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
262 subreq = cli_ntcreate_send(
263 state, ev, nb_state->cli, state->ft->cp.fname, flags,
264 desired_access, 0, share_mode,
265 state->ft->cp.cr_disposition,
266 state->ft->cp.cr_options,
267 SMB2_IMPERSONATION_IMPERSONATION, 0);
268 break;
270 case NBENCH_CMD_CLOSE: {
271 state->ft = ft_find(state->state->ftable,
272 ival(state->cmd->params[1]));
273 if (state->ft == NULL) {
274 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
275 return tevent_req_post(req, ev);
277 subreq = cli_close_send(
278 state, ev, nb_state->cli, state->ft->fnum);
279 break;
281 case NBENCH_CMD_MKDIR: {
282 char *fname;
283 fname = talloc_all_string_sub(
284 state, state->cmd->params[1], "client1",
285 nb_state->cliname);
286 if (tevent_req_nomem(state->ft->cp.fname, req)) {
287 return tevent_req_post(req, ev);
289 subreq = cli_mkdir_send(state, ev, nb_state->cli, fname);
290 break;
292 case NBENCH_CMD_QUERY_PATH_INFORMATION: {
293 char *fname;
294 fname = talloc_all_string_sub(
295 state, state->cmd->params[1], "client1",
296 nb_state->cliname);
297 if (tevent_req_nomem(state->ft->cp.fname, req)) {
298 return tevent_req_post(req, ev);
300 subreq = cli_qpathinfo_send(state, ev, nb_state->cli, fname,
301 ival(state->cmd->params[2]),
302 0, CLI_BUFFER_SIZE);
303 break;
305 default:
306 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
307 return tevent_req_post(req, ev);
310 if (tevent_req_nomem(subreq, req)) {
311 return tevent_req_post(req, ev);
313 tevent_req_set_callback(subreq, nbench_cmd_done, req);
314 return req;
317 static bool status_wrong(struct tevent_req *req, NTSTATUS expected,
318 NTSTATUS status)
320 if (NT_STATUS_EQUAL(expected, status)) {
321 return false;
323 if (NT_STATUS_IS_OK(status)) {
324 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
326 tevent_req_nterror(req, status);
327 return true;
330 static void nbench_cmd_done(struct tevent_req *subreq)
332 struct tevent_req *req = tevent_req_callback_data(
333 subreq, struct tevent_req);
334 struct nbench_cmd_state *state = tevent_req_data(
335 req, struct nbench_cmd_state);
336 struct nbench_state *nbstate = state->state;
337 NTSTATUS status;
339 switch (state->cmd->cmd) {
340 case NBENCH_CMD_NTCREATEX: {
341 struct ftable *ft;
342 status = cli_ntcreate_recv(subreq, &state->ft->fnum, NULL);
343 TALLOC_FREE(subreq);
344 if (status_wrong(req, state->cmd->status, status)) {
345 return;
347 if (!NT_STATUS_IS_OK(status)) {
348 tevent_req_done(req);
349 return;
351 ft = talloc_move(nbstate, &state->ft);
352 DLIST_ADD(nbstate->ftable, ft);
353 break;
355 case NBENCH_CMD_CLOSE: {
356 status = cli_close_recv(subreq);
357 TALLOC_FREE(subreq);
358 if (status_wrong(req, state->cmd->status, status)) {
359 return;
361 DLIST_REMOVE(state->state->ftable, state->ft);
362 TALLOC_FREE(state->ft);
363 break;
365 case NBENCH_CMD_MKDIR: {
366 status = cli_mkdir_recv(subreq);
367 TALLOC_FREE(subreq);
368 if (status_wrong(req, state->cmd->status, status)) {
369 return;
371 break;
373 case NBENCH_CMD_QUERY_PATH_INFORMATION: {
374 status = cli_qpathinfo_recv(subreq, NULL, NULL, NULL);
375 TALLOC_FREE(subreq);
376 if (status_wrong(req, state->cmd->status, status)) {
377 return;
379 break;
381 default:
382 break;
384 tevent_req_done(req);
387 static NTSTATUS nbench_cmd_recv(struct tevent_req *req)
389 return tevent_req_simple_recv_ntstatus(req);
392 static void nbench_done(struct tevent_req *subreq);
394 static struct tevent_req *nbench_send(
395 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
396 const char *cliname, FILE *loadfile,
397 void (*bw_report)(size_t nread, size_t nwritten, void *private_data),
398 void *bw_report_private)
400 struct tevent_req *req, *subreq;
401 struct nbench_state *state;
403 req = tevent_req_create(mem_ctx, &state, struct nbench_state);
404 if (req == NULL) {
405 return NULL;
407 state->ev = ev;
408 state->cli = cli;
409 state->cliname = cliname;
410 state->loadfile = loadfile;
411 state->bw_report = bw_report;
412 state->bw_report_private = bw_report_private;
414 subreq = nbench_cmd_send(state, ev, state);
415 if (tevent_req_nomem(subreq, req)) {
416 return tevent_req_post(req, ev);
418 tevent_req_set_callback(subreq, nbench_done, req);
419 return req;
422 static void nbench_done(struct tevent_req *subreq)
424 struct tevent_req *req = tevent_req_callback_data(
425 subreq, struct tevent_req);
426 struct nbench_state *state = tevent_req_data(
427 req, struct nbench_state);
428 NTSTATUS status;
430 status = nbench_cmd_recv(subreq);
431 TALLOC_FREE(subreq);
433 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
434 tevent_req_done(req);
435 return;
437 if (!NT_STATUS_IS_OK(status)) {
438 tevent_req_nterror(req, status);
439 return;
441 subreq = nbench_cmd_send(state, state->ev, state);
442 if (tevent_req_nomem(subreq, req)) {
443 return;
445 tevent_req_set_callback(subreq, nbench_done, req);
448 static NTSTATUS nbench_recv(struct tevent_req *req)
450 return tevent_req_simple_recv_ntstatus(req);
453 bool run_nbench2(int dummy)
455 TALLOC_CTX *frame = talloc_stackframe();
456 struct tevent_context *ev;
457 struct cli_state *cli = NULL;
458 FILE *loadfile;
459 bool ret = false;
460 struct tevent_req *req;
461 NTSTATUS status;
463 loadfile = fopen("client.txt", "r");
464 if (loadfile == NULL) {
465 fprintf(stderr, "Could not open \"client.txt\": %s\n",
466 strerror(errno));
467 return false;
469 ev = samba_tevent_context_init(talloc_tos());
470 if (ev == NULL) {
471 goto fail;
473 if (!torture_open_connection(&cli, 0)) {
474 goto fail;
477 req = nbench_send(talloc_tos(), ev, cli, "client1", loadfile,
478 NULL, NULL);
479 if (req == NULL) {
480 goto fail;
482 if (!tevent_req_poll(req, ev)) {
483 goto fail;
485 status = nbench_recv(req);
486 TALLOC_FREE(req);
487 printf("nbench returned %s\n", nt_errstr(status));
489 ret = true;
490 fail:
491 if (cli != NULL) {
492 torture_close_connection(cli);
494 TALLOC_FREE(ev);
495 if (loadfile != NULL) {
496 fclose(loadfile);
497 loadfile = NULL;
499 TALLOC_FREE(frame);
500 return ret;