1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00
samba-mirror/source4/ntvfs/nbench/vfs_nbench.c
Andrew Tridgell a3cec511bb r2561: completely redid the ntvfs module chaining code, You can now do something like:
ntvfs handler = nbench posix

and the nbench pass-thru module will be called before the posix
module. The chaining logic is now much saner, and less racy, with each
level in the chain getting its own private pointer rather than relying
on save/restore logic in the pass-thru module.

The only pass-thru module we have at the moment is the nbench one
(which records all traffic in a nbench compatibe format), but I plan
on soon writing a "unixuid" pass-thru module that will implement the
setegid()/setgroups()/seteuid() logic for standard posix uid
handling. This separation of the posix backend from the uid handling
should simplify the code, and make development easier.

I also modified the nbench module so it can do multiple chaining, so
if you want to you can do:

   ntvfs module = nbench nbench posix

and it will save 2 copies of the log file in /tmp. This is really only
useful for testing at the moment until we have more than one pass-thru
module.
(This used to be commit f84c0af35c)
2007-10-10 12:59:06 -05:00

689 lines
16 KiB
C

/*
Unix SMB/CIFS implementation.
a pass-thru NTVFS module to record a NBENCH load file
Copyright (C) Andrew Tridgell 2004
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
"passthru" in this module refers to the next level of NTVFS being used
*/
#include "includes.h"
/* this is stored in ntvfs_private */
struct nbench_private {
const struct ntvfs_ops *passthru_ops;
int log_fd;
};
/*
log one request to the nbench log
*/
static void nbench_log(struct nbench_private *private,
const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
static void nbench_log(struct nbench_private *private,
const char *format, ...)
{
va_list ap;
char *s = NULL;
va_start(ap, format);
vasprintf(&s, format, ap);
va_end(ap);
write(private->log_fd, s, strlen(s));
free(s);
}
/*
this is used to call the next module in the ntvfs chain
*/
#define PASS_THRU(tcon, op, args) private->passthru_ops->op args;
/*
this pass through macro operates on request contexts, and disables
async calls.
async calls are a pain for the nbench module as it makes pulling the
status code and any result parameters much harder.
*/
#define PASS_THRU_REQ(req, op, args) do { \
void *send_fn_saved = req->async.send_fn; \
req->async.send_fn = NULL; \
req->ntvfs_depth++; \
status = PASS_THRU(req->tcon, op, args); \
req->ntvfs_depth--; \
req->async.send_fn = send_fn_saved; \
} while (0)
/*
connect to a share - used when a tree_connect operation comes in.
*/
static NTSTATUS nbench_connect(struct smbsrv_request *req, const char *sharename, int depth)
{
struct nbench_private *private;
const char *passthru;
NTSTATUS status;
char *logname = NULL;
const char **handlers = lp_ntvfs_handler(req->tcon->service);
private = talloc_p(req->tcon, struct nbench_private);
if (!private) {
return NT_STATUS_NO_MEMORY;
}
asprintf(&logname, "/tmp/nbenchlog%d.%u", depth, getpid());
private->log_fd = open(logname, O_WRONLY|O_CREAT|O_APPEND, 0644);
free(logname);
if (private->log_fd == -1) {
DEBUG(0,("Failed to open nbench log\n"));
return NT_STATUS_UNSUCCESSFUL;
}
private->passthru_ops = ntvfs_backend_byname(handlers[depth+1], NTVFS_DISK);
if (!private->passthru_ops) {
DEBUG(0,("Unable to connect to '%s' pass through backend\n", passthru));
return NT_STATUS_UNSUCCESSFUL;
}
ntvfs_set_private(req->tcon, depth, private);
PASS_THRU(req->tcon, connect, (req, sharename, depth+1));
return status;
}
/*
disconnect from a share
*/
static NTSTATUS nbench_disconnect(struct smbsrv_tcon *tcon, int depth)
{
struct nbench_private *private = tcon->ntvfs_private_list[depth];
NTSTATUS status;
close(private->log_fd);
PASS_THRU(tcon, disconnect, (tcon, depth+1));
return status;
}
/*
delete a file - the dirtype specifies the file types to include in the search.
The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
*/
static NTSTATUS nbench_unlink(struct smbsrv_request *req, struct smb_unlink *unl)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, unlink, (req, unl));
nbench_log(private, "Unlink \"%s\" 0x%x %s\n",
unl->in.pattern, unl->in.attrib,
get_nt_error_c_code(status));
return status;
}
/*
ioctl interface
*/
static NTSTATUS nbench_ioctl(struct smbsrv_request *req, union smb_ioctl *io)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, ioctl, (req, io));
nbench_log(private, "Ioctl - NOT HANDLED\n");
return status;
}
/*
check if a directory exists
*/
static NTSTATUS nbench_chkpath(struct smbsrv_request *req, struct smb_chkpath *cp)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, chkpath, (req, cp));
nbench_log(private, "Chkpath \"%s\" %s\n",
cp->in.path,
get_nt_error_c_code(status));
return status;
}
/*
return info on a pathname
*/
static NTSTATUS nbench_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, qpathinfo, (req, info));
nbench_log(private, "QUERY_PATH_INFORMATION \"%s\" %d %s\n",
info->generic.in.fname,
info->generic.level,
get_nt_error_c_code(status));
return status;
}
/*
query info on a open file
*/
static NTSTATUS nbench_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, qfileinfo, (req, info));
nbench_log(private, "QUERY_FILE_INFORMATION %d %d %s\n",
info->generic.in.fnum,
info->generic.level,
get_nt_error_c_code(status));
return status;
}
/*
set info on a pathname
*/
static NTSTATUS nbench_setpathinfo(struct smbsrv_request *req, union smb_setfileinfo *st)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, setpathinfo, (req, st));
nbench_log(private, "SET_PATH_INFORMATION \"%s\" %d %s\n",
st->generic.file.fname,
st->generic.level,
get_nt_error_c_code(status));
return status;
}
/*
open a file
*/
static NTSTATUS nbench_open(struct smbsrv_request *req, union smb_open *io)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, open, (req, io));
switch (io->generic.level) {
case RAW_OPEN_NTCREATEX:
nbench_log(private, "NTCreateX \"%s\" 0x%x 0x%x %d %s\n",
io->ntcreatex.in.fname,
io->ntcreatex.in.create_options,
io->ntcreatex.in.open_disposition,
io->ntcreatex.out.fnum,
get_nt_error_c_code(status));
break;
default:
nbench_log(private, "Open-%d - NOT HANDLED\n",
io->generic.level);
break;
}
return status;
}
/*
create a directory
*/
static NTSTATUS nbench_mkdir(struct smbsrv_request *req, union smb_mkdir *md)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, mkdir, (req, md));
nbench_log(private, "Mkdir - NOT HANDLED\n");
return status;
}
/*
remove a directory
*/
static NTSTATUS nbench_rmdir(struct smbsrv_request *req, struct smb_rmdir *rd)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, rmdir, (req, rd));
nbench_log(private, "Rmdir \"%s\" %s\n",
rd->in.path,
get_nt_error_c_code(status));
return status;
}
/*
rename a set of files
*/
static NTSTATUS nbench_rename(struct smbsrv_request *req, union smb_rename *ren)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, rename, (req, ren));
switch (ren->generic.level) {
case RAW_RENAME_RENAME:
nbench_log(private, "Rename \"%s\" \"%s\" %s\n",
ren->rename.in.pattern1,
ren->rename.in.pattern2,
get_nt_error_c_code(status));
break;
default:
nbench_log(private, "Rename-%d - NOT HANDLED\n",
ren->generic.level);
break;
}
return status;
}
/*
copy a set of files
*/
static NTSTATUS nbench_copy(struct smbsrv_request *req, struct smb_copy *cp)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, copy, (req, cp));
nbench_log(private, "Copy - NOT HANDLED\n");
return status;
}
/*
read from a file
*/
static NTSTATUS nbench_read(struct smbsrv_request *req, union smb_read *rd)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, read, (req, rd));
switch (rd->generic.level) {
case RAW_READ_READX:
nbench_log(private, "ReadX %d %d %d %d %s\n",
rd->readx.in.fnum,
(int)rd->readx.in.offset,
rd->readx.in.maxcnt,
rd->readx.out.nread,
get_nt_error_c_code(status));
break;
default:
nbench_log(private, "Read-%d - NOT HANDLED\n",
rd->generic.level);
break;
}
return status;
}
/*
write to a file
*/
static NTSTATUS nbench_write(struct smbsrv_request *req, union smb_write *wr)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, write, (req, wr));
switch (wr->generic.level) {
case RAW_WRITE_WRITEX:
nbench_log(private, "WriteX %d %d %d %d %s\n",
wr->writex.in.fnum,
(int)wr->writex.in.offset,
wr->writex.in.count,
wr->writex.out.nwritten,
get_nt_error_c_code(status));
break;
case RAW_WRITE_WRITE:
nbench_log(private, "Write %d %d %d %d %s\n",
wr->write.in.fnum,
wr->write.in.offset,
wr->write.in.count,
wr->write.out.nwritten,
get_nt_error_c_code(status));
break;
default:
nbench_log(private, "Write-%d - NOT HANDLED\n",
wr->generic.level);
break;
}
return status;
}
/*
seek in a file
*/
static NTSTATUS nbench_seek(struct smbsrv_request *req, struct smb_seek *io)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, seek, (req, io));
nbench_log(private, "Seek - NOT HANDLED\n");
return status;
}
/*
flush a file
*/
static NTSTATUS nbench_flush(struct smbsrv_request *req, struct smb_flush *io)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, flush, (req, io));
nbench_log(private, "Flush %d %s\n",
io->in.fnum,
get_nt_error_c_code(status));
return status;
}
/*
close a file
*/
static NTSTATUS nbench_close(struct smbsrv_request *req, union smb_close *io)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, close, (req, io));
switch (io->generic.level) {
case RAW_CLOSE_CLOSE:
nbench_log(private, "Close %d %s\n",
io->close.in.fnum,
get_nt_error_c_code(status));
break;
default:
nbench_log(private, "Close-%d - NOT HANDLED\n",
io->generic.level);
break;
}
return status;
}
/*
exit - closing files
*/
static NTSTATUS nbench_exit(struct smbsrv_request *req)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, exit, (req));
return status;
}
/*
lock a byte range
*/
static NTSTATUS nbench_lock(struct smbsrv_request *req, union smb_lock *lck)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, lock, (req, lck));
if (lck->generic.level == RAW_LOCK_LOCKX &&
lck->lockx.in.lock_cnt == 1 &&
lck->lockx.in.ulock_cnt == 0) {
nbench_log(private, "LockX %d %d %d %s\n",
lck->lockx.in.fnum,
(int)lck->lockx.in.locks[0].offset,
(int)lck->lockx.in.locks[0].count,
get_nt_error_c_code(status));
} else if (lck->generic.level == RAW_LOCK_LOCKX &&
lck->lockx.in.ulock_cnt == 1) {
nbench_log(private, "UnlockX %d %d %d %s\n",
lck->lockx.in.fnum,
(int)lck->lockx.in.locks[0].offset,
(int)lck->lockx.in.locks[0].count,
get_nt_error_c_code(status));
} else {
nbench_log(private, "Lock-%d - NOT HANDLED\n", lck->generic.level);
}
return status;
}
/*
set info on a open file
*/
static NTSTATUS nbench_setfileinfo(struct smbsrv_request *req,
union smb_setfileinfo *info)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, setfileinfo, (req, info));
nbench_log(private, "SET_FILE_INFORMATION %d %d %s\n",
info->generic.file.fnum,
info->generic.level,
get_nt_error_c_code(status));
return status;
}
/*
return filesystem space info
*/
static NTSTATUS nbench_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, fsinfo, (req, fs));
nbench_log(private, "QUERY_FS_INFORMATION %d %s\n",
fs->generic.level,
get_nt_error_c_code(status));
return status;
}
/*
return print queue info
*/
static NTSTATUS nbench_lpq(struct smbsrv_request *req, union smb_lpq *lpq)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, lpq, (req, lpq));
nbench_log(private, "Lpq-%d - NOT HANDLED\n", lpq->generic.level);
return status;
}
/*
list files in a directory matching a wildcard pattern
*/
static NTSTATUS nbench_search_first(struct smbsrv_request *req, union smb_search_first *io,
void *search_private,
BOOL (*callback)(void *, union smb_search_data *))
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, search_first, (req, io, search_private, callback));
switch (io->generic.level) {
case RAW_SEARCH_BOTH_DIRECTORY_INFO:
nbench_log(private, "FIND_FIRST \"%s\" %d %d %d %s\n",
io->t2ffirst.in.pattern,
io->generic.level,
io->t2ffirst.in.max_count,
io->t2ffirst.out.count,
get_nt_error_c_code(status));
break;
default:
nbench_log(private, "Search-%d - NOT HANDLED\n", io->generic.level);
break;
}
return status;
}
/* continue a search */
static NTSTATUS nbench_search_next(struct smbsrv_request *req, union smb_search_next *io,
void *search_private,
BOOL (*callback)(void *, union smb_search_data *))
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, search_next, (req, io, search_private, callback));
nbench_log(private, "Searchnext-%d - NOT HANDLED\n", io->generic.level);
return status;
}
/* close a search */
static NTSTATUS nbench_search_close(struct smbsrv_request *req, union smb_search_close *io)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, search_close, (req, io));
nbench_log(private, "Searchclose-%d - NOT HANDLED\n", io->generic.level);
return status;
}
/* SMBtrans - not used on file shares */
static NTSTATUS nbench_trans(struct smbsrv_request *req, struct smb_trans2 *trans2)
{
NTVFS_GET_PRIVATE(nbench_private, private, req);
NTSTATUS status;
PASS_THRU_REQ(req, trans, (req,trans2));
nbench_log(private, "Trans - NOT HANDLED\n");
return status;
}
/*
initialise the nbench backend, registering ourselves with the ntvfs subsystem
*/
NTSTATUS ntvfs_nbench_init(void)
{
NTSTATUS ret;
struct ntvfs_ops ops;
ZERO_STRUCT(ops);
/* fill in the name and type */
ops.name = "nbench";
ops.type = NTVFS_DISK;
/* fill in all the operations */
ops.connect = nbench_connect;
ops.disconnect = nbench_disconnect;
ops.unlink = nbench_unlink;
ops.chkpath = nbench_chkpath;
ops.qpathinfo = nbench_qpathinfo;
ops.setpathinfo = nbench_setpathinfo;
ops.open = nbench_open;
ops.mkdir = nbench_mkdir;
ops.rmdir = nbench_rmdir;
ops.rename = nbench_rename;
ops.copy = nbench_copy;
ops.ioctl = nbench_ioctl;
ops.read = nbench_read;
ops.write = nbench_write;
ops.seek = nbench_seek;
ops.flush = nbench_flush;
ops.close = nbench_close;
ops.exit = nbench_exit;
ops.lock = nbench_lock;
ops.setfileinfo = nbench_setfileinfo;
ops.qfileinfo = nbench_qfileinfo;
ops.fsinfo = nbench_fsinfo;
ops.lpq = nbench_lpq;
ops.search_first = nbench_search_first;
ops.search_next = nbench_search_next;
ops.search_close = nbench_search_close;
ops.trans = nbench_trans;
/* we don't register a trans2 handler as we want to be able to
log individual trans2 requests */
ops.trans2 = NULL;
/* register ourselves with the NTVFS subsystem. */
ret = register_backend("ntvfs", &ops);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register nbench backend!\n"));
}
return ret;
}