2 Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2009
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
23 #include <sys/socket.h>
25 #include <libsmbclient.h>
28 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
30 static char *smb_domain;
31 static char *smb_user;
32 static char *smb_password;
34 typedef struct _data_t {
39 typedef struct _smb_handle_t {
43 /* a tree to store all open handles, indexed by path */
44 typedef struct _tree_t {
47 struct _tree_t *parent;
49 struct _tree_t *right;
52 static tree_t *open_files;
55 static tree_t *find_path(tree_t *tree, const char *path)
63 i = strcmp(path, tree->path.dptr);
68 return find_path(tree->left, path);
71 return find_path(tree->right, path);
74 static smb_handle_t *lookup_path(const char *path)
78 t = find_path(open_files, path);
86 static void free_node(tree_t *t)
88 free(discard_const(t->path.dptr));
92 static void delete_path(const char *path)
96 t = find_path(open_files, path);
101 /* we have a left child */
105 for(tmp_tree=t->left;tmp_tree->right;tmp_tree=tmp_tree->right)
107 tmp_tree->right = t->right;
109 t->right->parent = tmp_tree;
112 if (t->parent == NULL) {
113 open_files = tmp_tree;
114 tmp_tree->parent = NULL;
119 if (t->parent->left == t) {
120 t->parent->left = t->left;
122 t->left->parent = t->parent;
128 t->parent->right = t->left;
130 t->left->parent = t->parent;
136 /* we only have a right child */
140 for(tmp_tree=t->right;tmp_tree->left;tmp_tree=tmp_tree->left)
142 tmp_tree->left = t->left;
144 t->left->parent = tmp_tree;
147 if (t->parent == NULL) {
148 open_files = tmp_tree;
149 tmp_tree->parent = NULL;
154 if (t->parent->left == t) {
155 t->parent->left = t->right;
157 t->right->parent = t->parent;
163 t->parent->right = t->right;
165 t->right->parent = t->parent;
171 /* we are a leaf node */
172 if (t->parent == NULL) {
175 if (t->parent->left == t) {
176 t->parent->left = NULL;
178 t->parent->right = NULL;
185 static void insert_path(const char *path, smb_handle_t *hnd)
191 tmp_t = find_path(open_files, path);
196 t = malloc(sizeof(tree_t));
198 fprintf(stderr, "MALLOC failed to allocate tree_t in insert_fhandle\n");
202 t->path.dptr = strdup(path);
203 if (t->path.dptr == NULL) {
204 fprintf(stderr, "STRDUP failed to allocate key in insert_fhandle\n");
207 t->path.dsize = strlen(path);
215 if (open_files == NULL) {
222 i = strcmp(t->path.dptr, tmp_t->path.dptr);
224 tmp_t->handle = t->handle;
225 free(discard_const(t->path.dptr));
230 if (tmp_t->left == NULL) {
238 if (tmp_t->right == NULL) {
243 tmp_t = tmp_t->right;
255 static void failed(struct child_struct *child)
258 fprintf(stderr, "ERROR: child %d failed at line %d\n", child->id, child->line);
262 static int check_status(int ret, const char *status)
264 if (!strcmp(status, "*")) {
268 if ((!strcmp(status, "SUCCESS")) && (ret == 0)) {
272 if ((!strcmp(status, "ERROR")) && (ret != 0)) {
280 void smb_auth_fn(const char *server, const char *share, char *wrkgrp, int wrkgrplen, char *user, int userlen, char *passwd, int passwdlen)
285 if (smb_domain != NULL) {
286 strncpy(wrkgrp, smb_domain, wrkgrplen - 1); wrkgrp[wrkgrplen - 1] = 0;
288 strncpy(user, smb_user, userlen - 1); user[userlen - 1] = 0;
289 strncpy(passwd, smb_password, passwdlen - 1); passwd[passwdlen - 1] = 0;
292 static int smb_init(void)
299 if (options.smb_server == NULL) {
300 fprintf(stderr, "You must specify --smb-server=<server> with the \"smb\" backend.\n");
303 if (options.smb_share == NULL) {
304 fprintf(stderr, "You must specify --smb-share=<share> with the \"smb\" backend.\n");
307 if (options.smb_user == NULL) {
308 fprintf(stderr, "You must specify --smb-user=[<domain>/]<user>%%<password> with the \"smb\" backend.\n");
312 smb_domain = strdup(options.smb_user);
313 tmp = index(smb_domain, '/');
315 smb_user = smb_domain;
321 tmp = index(smb_user, '%');
325 smb_password = tmp+1;
329 ctx = smbc_new_context();
331 fprintf(stderr, "Could not allocate SMB Context\n");
335 smbc_setDebug(ctx, 0);
336 smbc_setFunctionAuthData(ctx, smb_auth_fn);
338 if (!smbc_init_context(ctx)) {
339 smbc_free_context(ctx, 0);
340 fprintf(stderr, "failed to initialize context\n");
343 smbc_set_context(ctx);
345 asprintf(&str, "smb://%s/%s", options.smb_server, options.smb_share);
346 ret = smbc_opendir(str);
350 fprintf(stderr, "Failed to access //%s/%s\n", options.smb_server, options.smb_share);
354 smbc_free_context(ctx, 1);
358 static void smb_setup(struct child_struct *child)
360 struct smb_child *ctx;
362 ctx = malloc(sizeof(struct smb_child));
364 fprintf(stderr, "Failed to malloc child ctx\n");
369 ctx->ctx = smbc_new_context();
370 if (ctx->ctx == NULL) {
371 fprintf(stderr, "Could not allocate SMB Context\n");
375 smbc_setDebug(ctx->ctx, 0);
376 smbc_setFunctionAuthData(ctx->ctx, smb_auth_fn);
378 if (!smbc_init_context(ctx->ctx)) {
379 smbc_free_context(ctx->ctx, 0);
380 fprintf(stderr, "failed to initialize context\n");
383 smbc_set_context(ctx->ctx);
386 static void smb_cleanup(struct child_struct *child)
388 struct smb_child *ctx = child->private;
390 smbc_free_context(ctx->ctx, 1);
394 static void smb_mkdir(struct dbench_op *op)
402 asprintf(&str, "smb://%s/%s/%s", options.smb_server, options.smb_share, dir);
404 ret = smbc_mkdir(str, 0777);
407 if (check_status(ret, op->status)) {
408 fprintf(stderr, "[%d] MKDIR \"%s\" failed - expected %s, got %d\n", op->child->line, dir, op->status, ret);
413 static void smb_rmdir(struct dbench_op *op)
420 asprintf(&str, "smb://%s/%s/%s", options.smb_server, options.smb_share, dir);
421 ret = smbc_rmdir(str);
424 if (check_status(ret, op->status)) {
425 fprintf(stderr, "[%d] RMDIR \"%s\" failed - expected %s, got %d\n", op->child->line, dir, op->status, ret);
430 static void smb_open(struct dbench_op *op)
437 if (op->params[0] & 0x01) {
440 if (op->params[0] & 0x02) {
443 if (op->params[0] & 0x04) {
446 if (op->params[0] & 0x08) {
449 if (op->params[0] & 0x10) {
452 if (op->params[0] & 0x20) {
455 if (op->params[0] & 0x40) {
459 file = op->fname + 2;
460 asprintf(&str, "smb://%s/%s/%s", options.smb_server, options.smb_share, file);
462 hnd.fd = smbc_open(str, flags, 0777);
465 if (check_status(hnd.fd<0?-1:0, op->status)) {
466 fprintf(stderr, "[%d] OPEN \"%s\" failed\n", op->child->line, file);
471 insert_path(file, &hnd);
475 static void smb_close(struct dbench_op *op)
481 file = op->fname + 2;
483 hnd = lookup_path(file);
485 fprintf(stderr, "[%d] CLOSE \"%s\" failed. This file is not open.\n", op->child->line, file);
490 ret = smbc_close(hnd->fd);
493 if (check_status(ret, op->status)) {
494 fprintf(stderr, "[%d] CLOSE \"%s\" failed\n", op->child->line, file);
500 static void smb_write(struct dbench_op *op)
509 offset = op->params[0];
510 length = op->params[1];
511 if (length > 65536) {
515 file = op->fname + 2;
517 hnd = lookup_path(file);
519 fprintf(stderr, "[%d] WRITE \"%s\" failed. This file is not open.\n", op->child->line, file);
525 smbc_lseek(hnd->fd, offset, SEEK_SET);
526 ret = smbc_write(hnd->fd, garbage, length);
528 if (check_status(ret==(int)length?0:-1, op->status)) {
529 fprintf(stderr, "[%d] WRITE \"%s\" failed\n", op->child->line, file);
535 static void smb_read(struct dbench_op *op)
544 offset = op->params[0];
545 length = op->params[1];
546 if (length > 65536) {
550 file = op->fname + 2;
552 hnd = lookup_path(file);
554 fprintf(stderr, "[%d] READ \"%s\" failed. This file is not open.\n", op->child->line, file);
560 smbc_lseek(hnd->fd, offset, SEEK_SET);
561 ret = smbc_read(hnd->fd, garbage, length);
563 if (check_status(ret==(int)length?0:-1, op->status)) {
564 fprintf(stderr, "[%d] READ \"%s\" failed\n", op->child->line, file);
571 static void smb_unlink(struct dbench_op *op)
577 path = op->fname + 2;
578 asprintf(&str, "smb://%s/%s/%s", options.smb_server, options.smb_share, path);
580 ret = smbc_unlink(str);
583 if (check_status(ret, op->status)) {
584 fprintf(stderr, "[%d] UNLINK \"%s\" failed\n", op->child->line, path);
591 static struct backend_op ops[] = {
592 { "CLOSE", smb_close },
593 { "MKDIR", smb_mkdir },
594 { "OPEN", smb_open },
595 { "READ", smb_read },
596 { "RMDIR", smb_rmdir },
597 { "UNLINK", smb_unlink },
598 { "WRITE", smb_write },
602 struct nb_operations smb_ops = {
603 .backend_name = "smbbench",
606 .cleanup = smb_cleanup,