e6f725a79086be4d764e9aab2603b5b8f9c885f6
[metze/samba/wip.git] / source4 / ntvfs / nbench / vfs_nbench.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    a pass-thru NTVFS module to record a NBENCH load file
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23   "passthru" in this module refers to the next level of NTVFS being used
24 */
25
26 #include "includes.h"
27 #include "ntvfs/ntvfs.h"
28 #include "system/filesys.h"
29
30 NTSTATUS ntvfs_nbench_init(void);
31
32 /* this is stored in ntvfs_private */
33 struct nbench_private {
34         int log_fd;
35 };
36
37 /*
38   log one request to the nbench log
39 */
40 static void nbench_log(struct ntvfs_request *req,
41                        const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
42
43 static void nbench_log(struct ntvfs_request *req,
44                        const char *format, ...)
45 {
46         struct nbench_private *nprivates = req->async_states->ntvfs->private_data;
47         va_list ap;
48         char *s = NULL;
49         int ret;
50
51         va_start(ap, format);
52         ret = vasprintf(&s, format, ap);
53         va_end(ap);
54
55         if (ret == -1) {
56                 return;
57         }
58
59         write(nprivates->log_fd, s, strlen(s));
60         free(s);
61 }
62
63 static char *nbench_ntvfs_handle_string(struct ntvfs_request *req, struct ntvfs_handle *h)
64 {
65         DATA_BLOB key;
66         uint16_t fnum = 0;
67
68         key = ntvfs_handle_get_wire_key(h, req);
69
70         switch (key.length) {
71         case 2: /* SMB fnum */
72                 fnum = SVAL(key.data, 0);
73                 break;
74         default:
75                 DEBUG(0,("%s: invalid wire handle size: %u\n",
76                         __FUNCTION__, (unsigned)key.length));
77                 break;
78         }
79
80         return talloc_asprintf(req, "%u", fnum);
81 }
82
83 /*
84   this pass through macro operates on request contexts, and disables
85   async calls. 
86
87   async calls are a pain for the nbench module as it makes pulling the
88   status code and any result parameters much harder.
89 */
90 #define PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1) do { \
91         status = ntvfs_async_state_push(ntvfs, req, par1, nbench_##op##_send); \
92         if (!NT_STATUS_IS_OK(status)) { \
93                 return status; \
94         } \
95 } while (0)
96
97 #define PASS_THRU_REQ_POST_ASYNC(req) do { \
98         req->async_states->status = status; \
99         if (!(req->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \
100                 req->async_states->send_fn(req); \
101         } \
102 } while (0)
103
104 #define PASS_THRU_REQ(ntvfs, req, op, par1, args) do { \
105         PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1); \
106         status = ntvfs_next_##op args; \
107         PASS_THRU_REQ_POST_ASYNC(req); \
108 } while (0)
109
110 #define PASS_THRU_REP_POST(req) do { \
111         ntvfs_async_state_pop(req); \
112         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { \
113                 req->async_states->send_fn(req); \
114         } \
115 } while (0)
116
117 /*
118   connect to a share - used when a tree_connect operation comes in.
119 */
120 static NTSTATUS nbench_connect(struct ntvfs_module_context *ntvfs,
121                                struct ntvfs_request *req,
122                                union smb_tcon* con)
123 {
124         struct nbench_private *nprivates;
125         NTSTATUS status;
126         char *logname = NULL;
127
128         nprivates = talloc(ntvfs, struct nbench_private);
129         if (!nprivates) {
130                 return NT_STATUS_NO_MEMORY;
131         }
132
133         logname = talloc_asprintf(req, "/tmp/nbenchlog%d.%u", ntvfs->depth,
134                                   (unsigned int)getpid());
135         NT_STATUS_HAVE_NO_MEMORY(logname);
136         nprivates->log_fd = open(logname, O_WRONLY|O_CREAT|O_APPEND, 0644);
137         talloc_free(logname);
138
139         if (nprivates->log_fd == -1) {
140                 DEBUG(0,("Failed to open nbench log\n"));
141                 return NT_STATUS_UNSUCCESSFUL;
142         }
143
144         ntvfs->private_data = nprivates;
145
146         status = ntvfs_next_connect(ntvfs, req, con);
147
148         return status;
149 }
150
151 /*
152   disconnect from a share
153 */
154 static NTSTATUS nbench_disconnect(struct ntvfs_module_context *ntvfs)
155 {
156         struct nbench_private *nprivates = ntvfs->private_data;
157         NTSTATUS status;
158
159         close(nprivates->log_fd);
160
161         status = ntvfs_next_disconnect(ntvfs);
162
163         return status;
164 }
165
166 /*
167   delete a file - the dirtype specifies the file types to include in the search. 
168   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
169 */
170 static void nbench_unlink_send(struct ntvfs_request *req)
171 {
172         union smb_unlink *unl = req->async_states->private_data;
173         nbench_log(req, "Unlink \"%s\" 0x%x %s\n", 
174                    unl->unlink.in.pattern, unl->unlink.in.attrib, 
175                    get_nt_error_c_code(req, req->async_states->status));
176
177         PASS_THRU_REP_POST(req);
178 }
179
180 static NTSTATUS nbench_unlink(struct ntvfs_module_context *ntvfs,
181                               struct ntvfs_request *req,
182                               union smb_unlink *unl)
183 {
184         NTSTATUS status;
185
186         PASS_THRU_REQ(ntvfs, req, unlink, unl, (ntvfs, req, unl));
187
188         return status;
189 }
190
191 /*
192   ioctl interface
193 */
194 static void nbench_ioctl_send(struct ntvfs_request *req)
195 {
196         nbench_log(req, "Ioctl - NOT HANDLED\n");
197
198         PASS_THRU_REP_POST(req);
199 }
200
201 static NTSTATUS nbench_ioctl(struct ntvfs_module_context *ntvfs,
202                              struct ntvfs_request *req, union smb_ioctl *io)
203 {
204         NTSTATUS status;
205
206         PASS_THRU_REQ(ntvfs, req, ioctl, io, (ntvfs, req, io));
207
208         return status;
209 }
210
211 /*
212   check if a directory exists
213 */
214 static void nbench_chkpath_send(struct ntvfs_request *req)
215 {
216         union smb_chkpath *cp = req->async_states->private_data;
217
218         nbench_log(req, "Chkpath \"%s\" %s\n", 
219                    cp->chkpath.in.path, 
220                    get_nt_error_c_code(req, req->async_states->status));
221
222         PASS_THRU_REP_POST(req);
223 }
224
225 static NTSTATUS nbench_chkpath(struct ntvfs_module_context *ntvfs,
226                                struct ntvfs_request *req,
227                                union smb_chkpath *cp)
228 {
229         NTSTATUS status;
230
231         PASS_THRU_REQ(ntvfs, req, chkpath, cp, (ntvfs, req, cp));
232
233         return status;
234 }
235
236 /*
237   return info on a pathname
238 */
239 static void nbench_qpathinfo_send(struct ntvfs_request *req)
240 {
241         union smb_fileinfo *info = req->async_states->private_data;
242
243         nbench_log(req, "QUERY_PATH_INFORMATION \"%s\" %d %s\n", 
244                    info->generic.in.file.path, 
245                    info->generic.level,
246                    get_nt_error_c_code(req, req->async_states->status));
247
248         PASS_THRU_REP_POST(req);
249 }
250
251 static NTSTATUS nbench_qpathinfo(struct ntvfs_module_context *ntvfs,
252                                  struct ntvfs_request *req, union smb_fileinfo *info)
253 {
254         NTSTATUS status;
255
256         PASS_THRU_REQ(ntvfs, req, qpathinfo, info, (ntvfs, req, info));
257
258         return status;
259 }
260
261 /*
262   query info on a open file
263 */
264 static void nbench_qfileinfo_send(struct ntvfs_request *req)
265 {
266         union smb_fileinfo *info = req->async_states->private_data;
267
268         nbench_log(req, "QUERY_FILE_INFORMATION %s %d %s\n", 
269                    nbench_ntvfs_handle_string(req, info->generic.in.file.ntvfs),
270                    info->generic.level,
271                    get_nt_error_c_code(req, req->async_states->status));
272
273         PASS_THRU_REP_POST(req);
274 }
275
276 static NTSTATUS nbench_qfileinfo(struct ntvfs_module_context *ntvfs,
277                                  struct ntvfs_request *req, union smb_fileinfo *info)
278 {
279         NTSTATUS status;
280
281         PASS_THRU_REQ(ntvfs, req, qfileinfo, info, (ntvfs, req, info));
282
283         return status;
284 }
285
286 /*
287   set info on a pathname
288 */
289 static void nbench_setpathinfo_send(struct ntvfs_request *req)
290 {
291         union smb_setfileinfo *st = req->async_states->private_data;
292
293         nbench_log(req, "SET_PATH_INFORMATION \"%s\" %d %s\n", 
294                    st->generic.in.file.path, 
295                    st->generic.level,
296                    get_nt_error_c_code(req, req->async_states->status));
297
298         PASS_THRU_REP_POST(req);
299 }
300
301 static NTSTATUS nbench_setpathinfo(struct ntvfs_module_context *ntvfs,
302                                    struct ntvfs_request *req, union smb_setfileinfo *st)
303 {
304         NTSTATUS status;
305
306         PASS_THRU_REQ(ntvfs, req, setpathinfo, st, (ntvfs, req, st));
307
308         return status;
309 }
310
311 /*
312   open a file
313 */
314 static void nbench_open_send(struct ntvfs_request *req)
315 {
316         union smb_open *io = req->async_states->private_data;
317
318         switch (io->generic.level) {
319         case RAW_OPEN_NTCREATEX:
320                 if (!NT_STATUS_IS_OK(req->async_states->status)) {
321                         ZERO_STRUCT(io->ntcreatex.out);
322                 }
323                 nbench_log(req, "NTCreateX \"%s\" 0x%x 0x%x %s %s\n", 
324                            io->ntcreatex.in.fname, 
325                            io->ntcreatex.in.create_options, 
326                            io->ntcreatex.in.open_disposition, 
327                            nbench_ntvfs_handle_string(req, io->ntcreatex.out.file.ntvfs),
328                            get_nt_error_c_code(req, req->async_states->status));
329                 break;
330
331         default:
332                 nbench_log(req, "Open-%d - NOT HANDLED\n",
333                            io->generic.level);
334                 break;
335         }
336
337         PASS_THRU_REP_POST(req);
338 }
339
340 static NTSTATUS nbench_open(struct ntvfs_module_context *ntvfs,
341                             struct ntvfs_request *req, union smb_open *io)
342 {
343         NTSTATUS status;
344
345 #undef open /* AIX defines open to be open64 */
346         PASS_THRU_REQ(ntvfs, req, open, io, (ntvfs, req, io));
347
348         return status;
349 }
350
351 /*
352   create a directory
353 */
354 static void nbench_mkdir_send(struct ntvfs_request *req)
355 {
356         nbench_log(req, "Mkdir - NOT HANDLED\n");
357
358         PASS_THRU_REP_POST(req);
359 }
360
361 static NTSTATUS nbench_mkdir(struct ntvfs_module_context *ntvfs,
362                              struct ntvfs_request *req, union smb_mkdir *md)
363 {
364         NTSTATUS status;
365
366         PASS_THRU_REQ(ntvfs, req, mkdir, md, (ntvfs, req, md));
367
368         return status;
369 }
370
371 /*
372   remove a directory
373 */
374 static void nbench_rmdir_send(struct ntvfs_request *req)
375 {
376         struct smb_rmdir *rd = req->async_states->private_data;
377
378         nbench_log(req, "Rmdir \"%s\" %s\n", 
379                    rd->in.path, 
380                    get_nt_error_c_code(req, req->async_states->status));
381
382         PASS_THRU_REP_POST(req);
383 }
384
385 static NTSTATUS nbench_rmdir(struct ntvfs_module_context *ntvfs,
386                              struct ntvfs_request *req, struct smb_rmdir *rd)
387 {
388         NTSTATUS status;
389
390         PASS_THRU_REQ(ntvfs, req, rmdir, rd, (ntvfs, req, rd));
391
392         return status;
393 }
394
395 /*
396   rename a set of files
397 */
398 static void nbench_rename_send(struct ntvfs_request *req)
399 {
400         union smb_rename *ren = req->async_states->private_data;
401
402         switch (ren->generic.level) {
403         case RAW_RENAME_RENAME:
404                 nbench_log(req, "Rename \"%s\" \"%s\" %s\n", 
405                            ren->rename.in.pattern1, 
406                            ren->rename.in.pattern2, 
407                            get_nt_error_c_code(req, req->async_states->status));
408                 break;
409
410         default:
411                 nbench_log(req, "Rename-%d - NOT HANDLED\n",
412                            ren->generic.level);
413                 break;
414         }
415
416         PASS_THRU_REP_POST(req);
417 }
418
419 static NTSTATUS nbench_rename(struct ntvfs_module_context *ntvfs,
420                               struct ntvfs_request *req, union smb_rename *ren)
421 {
422         NTSTATUS status;
423
424         PASS_THRU_REQ(ntvfs, req, rename, ren, (ntvfs, req, ren));
425
426         return status;
427 }
428
429 /*
430   copy a set of files
431 */
432 static void nbench_copy_send(struct ntvfs_request *req)
433 {
434         nbench_log(req, "Copy - NOT HANDLED\n");
435
436         PASS_THRU_REP_POST(req);
437 }
438
439 static NTSTATUS nbench_copy(struct ntvfs_module_context *ntvfs,
440                             struct ntvfs_request *req, struct smb_copy *cp)
441 {
442         NTSTATUS status;
443
444         PASS_THRU_REQ(ntvfs, req, copy, cp, (ntvfs, req, cp));
445
446         return status;
447 }
448
449 /*
450   read from a file
451 */
452 static void nbench_read_send(struct ntvfs_request *req)
453 {
454         union smb_read *rd = req->async_states->private_data;
455         
456         switch (rd->generic.level) {
457         case RAW_READ_READX:
458                 if (!NT_STATUS_IS_OK(req->async_states->status)) {
459                         ZERO_STRUCT(rd->readx.out);
460                 }
461                 nbench_log(req, "ReadX %s %d %d %d %s\n", 
462                            nbench_ntvfs_handle_string(req, rd->readx.in.file.ntvfs),
463                            (int)rd->readx.in.offset,
464                            rd->readx.in.maxcnt,
465                            rd->readx.out.nread,
466                            get_nt_error_c_code(req, req->async_states->status));
467                 break;
468         default:
469                 nbench_log(req, "Read-%d - NOT HANDLED\n",
470                            rd->generic.level);
471                 break;
472         }
473
474         PASS_THRU_REP_POST(req);
475 }
476
477 static NTSTATUS nbench_read(struct ntvfs_module_context *ntvfs,
478                             struct ntvfs_request *req, union smb_read *rd)
479 {
480         NTSTATUS status;
481
482         PASS_THRU_REQ(ntvfs, req, read, rd, (ntvfs, req, rd));
483
484         return status;
485 }
486
487 /*
488   write to a file
489 */
490 static void nbench_write_send(struct ntvfs_request *req)
491 {
492         union smb_write *wr = req->async_states->private_data;
493
494         switch (wr->generic.level) {
495         case RAW_WRITE_WRITEX:
496                 if (!NT_STATUS_IS_OK(req->async_states->status)) {
497                         ZERO_STRUCT(wr->writex.out);
498                 }
499                 nbench_log(req, "WriteX %s %d %d %d %s\n", 
500                            nbench_ntvfs_handle_string(req, wr->writex.in.file.ntvfs),
501                            (int)wr->writex.in.offset,
502                            wr->writex.in.count,
503                            wr->writex.out.nwritten,
504                            get_nt_error_c_code(req, req->async_states->status));
505                 break;
506
507         case RAW_WRITE_WRITE:
508                 if (!NT_STATUS_IS_OK(req->async_states->status)) {
509                         ZERO_STRUCT(wr->write.out);
510                 }
511                 nbench_log(req, "Write %s %d %d %d %s\n", 
512                            nbench_ntvfs_handle_string(req, wr->write.in.file.ntvfs),
513                            wr->write.in.offset,
514                            wr->write.in.count,
515                            wr->write.out.nwritten,
516                            get_nt_error_c_code(req, req->async_states->status));
517                 break;
518
519         default:
520                 nbench_log(req, "Write-%d - NOT HANDLED\n",
521                            wr->generic.level);
522                 break;
523         }
524
525         PASS_THRU_REP_POST(req);
526 }
527
528 static NTSTATUS nbench_write(struct ntvfs_module_context *ntvfs,
529                              struct ntvfs_request *req, union smb_write *wr)
530 {
531         NTSTATUS status;
532
533         PASS_THRU_REQ(ntvfs, req, write, wr, (ntvfs, req, wr));
534
535         return status;
536 }
537
538 /*
539   seek in a file
540 */
541 static void nbench_seek_send(struct ntvfs_request *req)
542 {
543         nbench_log(req, "Seek - NOT HANDLED\n");
544
545         PASS_THRU_REP_POST(req);
546 }
547
548 static NTSTATUS nbench_seek(struct ntvfs_module_context *ntvfs,
549                             struct ntvfs_request *req,
550                             union smb_seek *io)
551 {
552         NTSTATUS status;
553
554         PASS_THRU_REQ(ntvfs, req, seek, io, (ntvfs, req, io));
555
556         return status;
557 }
558
559 /*
560   flush a file
561 */
562 static void nbench_flush_send(struct ntvfs_request *req)
563 {
564         union smb_flush *io = req->async_states->private_data;
565
566         switch (io->generic.level) {
567         case RAW_FLUSH_FLUSH:
568                 nbench_log(req, "Flush %s %s\n",
569                            nbench_ntvfs_handle_string(req, io->flush.in.file.ntvfs),
570                            get_nt_error_c_code(req, req->async_states->status));
571                 break;
572         case RAW_FLUSH_ALL:
573                 nbench_log(req, "Flush %d %s\n",
574                            0xFFFF,
575                            get_nt_error_c_code(req, req->async_states->status));
576                 break;
577         default:
578                 nbench_log(req, "Flush-%d - NOT HANDLED\n",
579                            io->generic.level);
580                 break;
581         }
582
583         PASS_THRU_REP_POST(req);
584 }
585
586 static NTSTATUS nbench_flush(struct ntvfs_module_context *ntvfs,
587                              struct ntvfs_request *req,
588                              union smb_flush *io)
589 {
590         NTSTATUS status;
591
592         PASS_THRU_REQ(ntvfs, req, flush, io, (ntvfs, req, io));
593
594         return status;
595 }
596
597 /*
598   close a file
599 */
600 static void nbench_close_send(struct ntvfs_request *req)
601 {
602         union smb_close *io = req->async_states->private_data;
603
604         switch (io->generic.level) {
605         case RAW_CLOSE_CLOSE:
606                 nbench_log(req, "Close %s %s\n",
607                            nbench_ntvfs_handle_string(req, io->close.in.file.ntvfs),
608                            get_nt_error_c_code(req, req->async_states->status));
609                 break;
610
611         default:
612                 nbench_log(req, "Close-%d - NOT HANDLED\n",
613                            io->generic.level);
614                 break;
615         }               
616
617         PASS_THRU_REP_POST(req);
618 }
619
620 static NTSTATUS nbench_close(struct ntvfs_module_context *ntvfs,
621                              struct ntvfs_request *req, union smb_close *io)
622 {
623         NTSTATUS status;
624
625         PASS_THRU_REQ(ntvfs, req, close, io, (ntvfs, req, io));
626
627         return status;
628 }
629
630 /*
631   exit - closing files
632 */
633 static void nbench_exit_send(struct ntvfs_request *req)
634 {
635         nbench_log(req, "Exit - NOT HANDLED\n");
636
637         PASS_THRU_REP_POST(req);
638 }
639
640 static NTSTATUS nbench_exit(struct ntvfs_module_context *ntvfs,
641                             struct ntvfs_request *req)
642 {
643         NTSTATUS status;
644
645         PASS_THRU_REQ(ntvfs, req, exit, NULL, (ntvfs, req));
646
647         return status;
648 }
649
650 /*
651   logoff - closing files
652 */
653 static void nbench_logoff_send(struct ntvfs_request *req)
654 {
655         nbench_log(req, "Logoff - NOT HANDLED\n");
656
657         PASS_THRU_REP_POST(req);
658 }
659
660 static NTSTATUS nbench_logoff(struct ntvfs_module_context *ntvfs,
661                               struct ntvfs_request *req)
662 {
663         NTSTATUS status;
664
665         PASS_THRU_REQ(ntvfs, req, logoff, NULL, (ntvfs, req));
666
667         return status;
668 }
669
670 /*
671   async_setup - send fn
672 */
673 static void nbench_async_setup_send(struct ntvfs_request *req)
674 {
675         PASS_THRU_REP_POST(req);
676 }
677
678 /*
679   async setup
680 */
681 static NTSTATUS nbench_async_setup(struct ntvfs_module_context *ntvfs,
682                                    struct ntvfs_request *req,
683                                    void *private_data)
684 {
685         NTSTATUS status;
686
687         PASS_THRU_REQ(ntvfs, req, async_setup, NULL, (ntvfs, req, private_data));
688
689         return status;
690 }
691
692
693 static void nbench_cancel_send(struct ntvfs_request *req)
694 {
695         PASS_THRU_REP_POST(req);
696 }
697
698 /*
699   cancel an existing async request
700 */
701 static NTSTATUS nbench_cancel(struct ntvfs_module_context *ntvfs,
702                               struct ntvfs_request *req)
703 {
704         NTSTATUS status;
705
706         PASS_THRU_REQ(ntvfs, req, cancel, NULL, (ntvfs, req));
707
708         return status;
709 }
710
711 /*
712   lock a byte range
713 */
714 static void nbench_lock_send(struct ntvfs_request *req)
715 {
716         union smb_lock *lck = req->async_states->private_data;
717
718         if (lck->generic.level == RAW_LOCK_LOCKX &&
719             lck->lockx.in.lock_cnt == 1 &&
720             lck->lockx.in.ulock_cnt == 0) {
721                 nbench_log(req, "LockX %s %d %d %s\n", 
722                            nbench_ntvfs_handle_string(req, lck->lockx.in.file.ntvfs),
723                            (int)lck->lockx.in.locks[0].offset,
724                            (int)lck->lockx.in.locks[0].count,
725                            get_nt_error_c_code(req, req->async_states->status));
726         } else if (lck->generic.level == RAW_LOCK_LOCKX &&
727                    lck->lockx.in.ulock_cnt == 1) {
728                 nbench_log(req, "UnlockX %s %d %d %s\n", 
729                            nbench_ntvfs_handle_string(req, lck->lockx.in.file.ntvfs),
730                            (int)lck->lockx.in.locks[0].offset,
731                            (int)lck->lockx.in.locks[0].count,
732                            get_nt_error_c_code(req, req->async_states->status));
733         } else {
734                 nbench_log(req, "Lock-%d - NOT HANDLED\n", lck->generic.level);
735         }
736
737         PASS_THRU_REP_POST(req);
738 }
739
740 static NTSTATUS nbench_lock(struct ntvfs_module_context *ntvfs,
741                             struct ntvfs_request *req, union smb_lock *lck)
742 {
743         NTSTATUS status;
744
745         PASS_THRU_REQ(ntvfs, req, lock, lck, (ntvfs, req, lck));
746
747         return status;
748 }
749
750 /*
751   set info on a open file
752 */
753 static void nbench_setfileinfo_send(struct ntvfs_request *req)
754 {
755         union smb_setfileinfo *info = req->async_states->private_data;
756
757         nbench_log(req, "SET_FILE_INFORMATION %s %d %s\n", 
758                    nbench_ntvfs_handle_string(req, info->generic.in.file.ntvfs),
759                    info->generic.level,
760                    get_nt_error_c_code(req, req->async_states->status));
761
762         PASS_THRU_REP_POST(req);
763 }
764
765 static NTSTATUS nbench_setfileinfo(struct ntvfs_module_context *ntvfs,
766                                    struct ntvfs_request *req, 
767                                    union smb_setfileinfo *info)
768 {
769         NTSTATUS status;
770
771         PASS_THRU_REQ(ntvfs, req, setfileinfo, info, (ntvfs, req, info));
772
773         return status;
774 }
775
776 /*
777   return filesystem space info
778 */
779 static void nbench_fsinfo_send(struct ntvfs_request *req)
780 {
781         union smb_fsinfo *fs = req->async_states->private_data;
782
783         nbench_log(req, "QUERY_FS_INFORMATION %d %s\n", 
784                    fs->generic.level, 
785                    get_nt_error_c_code(req, req->async_states->status));
786
787         PASS_THRU_REP_POST(req);
788 }
789
790 static NTSTATUS nbench_fsinfo(struct ntvfs_module_context *ntvfs,
791                               struct ntvfs_request *req, union smb_fsinfo *fs)
792 {
793         NTSTATUS status;
794
795         PASS_THRU_REQ(ntvfs, req, fsinfo, fs, (ntvfs, req, fs));
796
797         return status;
798 }
799
800 /*
801   return print queue info
802 */
803 static void nbench_lpq_send(struct ntvfs_request *req)
804 {
805         union smb_lpq *lpq = req->async_states->private_data;
806
807         nbench_log(req, "Lpq-%d - NOT HANDLED\n", lpq->generic.level);
808
809         PASS_THRU_REP_POST(req);
810 }
811
812 static NTSTATUS nbench_lpq(struct ntvfs_module_context *ntvfs,
813                            struct ntvfs_request *req, union smb_lpq *lpq)
814 {
815         NTSTATUS status;
816
817         PASS_THRU_REQ(ntvfs, req, lpq, lpq, (ntvfs, req, lpq));
818
819         return status;
820 }
821
822 /* 
823    list files in a directory matching a wildcard pattern
824 */
825 static void nbench_search_first_send(struct ntvfs_request *req)
826 {
827         union smb_search_first *io = req->async_states->private_data;
828         
829         switch (io->generic.level) {
830         case RAW_SEARCH_TRANS2:
831                 if (NT_STATUS_IS_ERR(req->async_states->status)) {
832                         ZERO_STRUCT(io->t2ffirst.out);
833                 }
834                 nbench_log(req, "FIND_FIRST \"%s\" %d %d %d %s\n", 
835                            io->t2ffirst.in.pattern,
836                            io->t2ffirst.data_level,
837                            io->t2ffirst.in.max_count,
838                            io->t2ffirst.out.count,
839                            get_nt_error_c_code(req, req->async_states->status));
840                 break;
841                 
842         default:
843                 nbench_log(req, "Search-%d - NOT HANDLED\n", io->generic.level);
844                 break;
845         }
846
847         PASS_THRU_REP_POST(req);
848 }
849
850 static NTSTATUS nbench_search_first(struct ntvfs_module_context *ntvfs,
851                                     struct ntvfs_request *req, union smb_search_first *io, 
852                                     void *search_private, 
853                                     bool (*callback)(void *, const union smb_search_data *))
854 {
855         NTSTATUS status;
856
857         PASS_THRU_REQ(ntvfs, req, search_first, io, (ntvfs, req, io, search_private, callback));
858
859         return status;
860 }
861
862 /* continue a search */
863 static void nbench_search_next_send(struct ntvfs_request *req)
864 {
865         union smb_search_next *io = req->async_states->private_data;
866
867         nbench_log(req, "Searchnext-%d - NOT HANDLED\n", io->generic.level);
868
869         PASS_THRU_REP_POST(req);
870 }
871
872 static NTSTATUS nbench_search_next(struct ntvfs_module_context *ntvfs,
873                                    struct ntvfs_request *req, union smb_search_next *io, 
874                                    void *search_private, 
875                                    bool (*callback)(void *, const union smb_search_data *))
876 {
877         NTSTATUS status;
878
879         PASS_THRU_REQ(ntvfs, req, search_next, io, (ntvfs, req, io, search_private, callback));
880
881         return status;
882 }
883
884 /* close a search */
885 static void nbench_search_close_send(struct ntvfs_request *req)
886 {
887         union smb_search_close *io = req->async_states->private_data;
888
889         nbench_log(req, "Searchclose-%d - NOT HANDLED\n", io->generic.level);
890
891         PASS_THRU_REP_POST(req);
892 }
893
894 static NTSTATUS nbench_search_close(struct ntvfs_module_context *ntvfs,
895                                     struct ntvfs_request *req, union smb_search_close *io)
896 {
897         NTSTATUS status;
898
899         PASS_THRU_REQ(ntvfs, req, search_close, io, (ntvfs, req, io));
900
901         return status;
902 }
903
904 /* SMBtrans - not used on file shares */
905 static void nbench_trans_send(struct ntvfs_request *req)
906 {
907         nbench_log(req, "Trans - NOT HANDLED\n");
908
909         PASS_THRU_REP_POST(req);
910 }
911
912 static NTSTATUS nbench_trans(struct ntvfs_module_context *ntvfs,
913                              struct ntvfs_request *req, struct smb_trans2 *trans2)
914 {
915         NTSTATUS status;
916
917         PASS_THRU_REQ(ntvfs, req, trans, trans2, (ntvfs, req, trans2));
918
919         return status;
920 }
921
922 /*
923   initialise the nbench backend, registering ourselves with the ntvfs subsystem
924  */
925 NTSTATUS ntvfs_nbench_init(void)
926 {
927         NTSTATUS ret;
928         struct ntvfs_ops ops;
929         NTVFS_CURRENT_CRITICAL_SIZES(vers);
930
931         ZERO_STRUCT(ops);
932
933         /* fill in the name and type */
934         ops.name = "nbench";
935         ops.type = NTVFS_DISK;
936         
937         /* fill in all the operations */
938         ops.connect_fn = nbench_connect;
939         ops.disconnect_fn = nbench_disconnect;
940         ops.unlink_fn = nbench_unlink;
941         ops.chkpath_fn = nbench_chkpath;
942         ops.qpathinfo_fn = nbench_qpathinfo;
943         ops.setpathinfo_fn = nbench_setpathinfo;
944         ops.open_fn = nbench_open;
945         ops.mkdir_fn = nbench_mkdir;
946         ops.rmdir_fn = nbench_rmdir;
947         ops.rename_fn = nbench_rename;
948         ops.copy_fn = nbench_copy;
949         ops.ioctl_fn = nbench_ioctl;
950         ops.read_fn = nbench_read;
951         ops.write_fn = nbench_write;
952         ops.seek_fn = nbench_seek;
953         ops.flush_fn = nbench_flush;
954         ops.close_fn = nbench_close;
955         ops.exit_fn = nbench_exit;
956         ops.lock_fn = nbench_lock;
957         ops.setfileinfo_fn = nbench_setfileinfo;
958         ops.qfileinfo_fn = nbench_qfileinfo;
959         ops.fsinfo_fn = nbench_fsinfo;
960         ops.lpq_fn = nbench_lpq;
961         ops.search_first_fn = nbench_search_first;
962         ops.search_next_fn = nbench_search_next;
963         ops.search_close_fn = nbench_search_close;
964         ops.trans_fn = nbench_trans;
965         ops.logoff_fn = nbench_logoff;
966         ops.async_setup_fn = nbench_async_setup;
967         ops.cancel_fn = nbench_cancel;
968
969         /* we don't register a trans2 handler as we want to be able to
970            log individual trans2 requests */
971         ops.trans2_fn = NULL;
972
973         /* register ourselves with the NTVFS subsystem. */
974         ret = ntvfs_register(&ops, &vers);
975
976         if (!NT_STATUS_IS_OK(ret)) {
977                 DEBUG(0,("Failed to register nbench backend!\n"));
978         }
979         
980         return ret;
981 }