r25000: Fix some more C++ compatibility warnings.
[gd/samba-autobuild/.git] / source4 / torture / nbench / nbio.c
1 /*
2   TODO: add splitting of writes for servers with signing
3 */
4
5
6 /* 
7    Unix SMB/CIFS implementation.
8    SMB torture tester
9    Copyright (C) Andrew Tridgell 1997-1998
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "system/time.h"
27 #include "system/filesys.h"
28 #include "lib/util/dlinklist.h"
29 #include "libcli/libcli.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "torture/torture.h"
32 #include "libcli/libcli.h"
33 #include "torture/util.h"
34 #include "torture/nbench/proto.h"
35
36 extern int nbench_line_count;
37 static int nbio_id = -1;
38 static int nprocs;
39 static BOOL bypass_io;
40 static struct timeval tv_start, tv_end;
41 static int warmup, timelimit;
42 static int in_cleanup;
43
44 struct lock_info {
45         struct lock_info *next, *prev;
46         off_t offset;
47         int size;
48 };
49
50 struct createx_params {
51         char *fname;
52         uint_t create_options;
53         uint_t create_disposition;
54         int handle;
55 };
56
57 struct ftable {
58         struct ftable *next, *prev;
59         int fd;     /* the fd that we got back from the server */
60         int handle; /* the handle in the load file */
61         struct createx_params cp;
62         struct lock_info *locks;
63 };
64
65 static struct ftable *ftable;
66
67 static struct {
68         double bytes, warmup_bytes;
69         int line;
70         int done;
71         bool connected;
72         double max_latency;
73         struct timeval starttime;
74 } *children;
75
76 static bool nb_do_createx(struct ftable *f,
77                           const char *fname,
78                           uint_t create_options,
79                           uint_t create_disposition,
80                           int handle,
81                           NTSTATUS status,
82                           bool retry);
83
84 static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status);
85
86 static void nb_set_createx_params(struct ftable *f,
87                                   const char *fname,
88                                   uint_t create_options,
89                                   uint_t create_disposition,
90                                   int handle)
91 {
92         struct createx_params *cp = &f->cp;
93
94         if (fname != NULL) {
95                 cp->fname = talloc_strdup(f, fname);
96                 if (cp->fname == NULL) {
97                         perror("nb_set_createx_params: strdup");
98                         nb_exit(1);
99                 }
100         } else {
101                 cp->fname = NULL;
102         }
103
104         cp->create_options = create_options;
105         cp->create_disposition = create_disposition;
106         cp->handle = handle;
107 }
108
109 static bool nb_reestablish_locks(struct ftable *f)
110 {
111         struct lock_info *linfo = f->locks;
112
113         while (linfo != NULL) {
114                 DEBUG(1,("nb_reestablish_locks: lock for file %d at %lu\n",
115                          f->handle, (unsigned long) linfo->offset));
116
117                 if (!nb_do_lockx(true, f->handle, linfo->offset, linfo->size, NT_STATUS_OK)) {
118                         printf("nb_reestablish_locks: failed to get lock for file %s at %lu\n",
119                                f->cp.fname, (unsigned long) linfo->offset);
120                         return False;
121                 }
122
123                 linfo = linfo->next;
124         }
125
126         return True;
127 }
128
129 static bool nb_reopen_all_files(void)
130 {
131         struct ftable *f = ftable;
132
133         while (f != NULL) {
134                 DEBUG(1,("-- nb_reopen_all_files: opening %s (handle %d)\n",
135                          f->cp.fname, f->cp.handle));
136
137                 if (!nb_do_createx(f,
138                                    f->cp.fname,
139                                    f->cp.create_options,
140                                    f->cp.create_disposition,
141                                    f->cp.handle,
142                                    NT_STATUS_OK,
143                                    True))
144                 {
145                         printf("-- nb_reopen_all_files: failed to open file %s\n", f->cp.fname);
146                         return False;
147                 }
148
149                 if (!nb_reestablish_locks(f)) {
150                         printf("--nb_reopen_all_files: failed to reestablish locks\n");
151                         return False;
152                 }
153
154                 f = f->next;
155         }
156
157         return True;
158 }
159
160 bool nb_reconnect(struct smbcli_state **cli, int client)
161 {
162         children[client].connected = false;
163
164         if (*cli != NULL) {
165                 talloc_free(*cli);
166         }
167
168         if (!torture_open_connection(cli, client)) {
169                 printf("nb_reconnect: failed to connect\n");
170                 *cli = NULL;
171                 return False;
172         }
173
174         nb_setup(*cli, client);
175
176         if (!nb_reopen_all_files()) {
177                 printf("nb_reconnect: failed to reopen files in client %d\n", client);
178                 return False;
179         }
180
181         return True;
182 }
183
184 void nbio_target_rate(double rate)
185 {
186         static double last_bytes;
187         static struct timeval last_time;
188         double tdelay;
189
190         if (last_bytes == 0) {
191                 last_bytes = children[nbio_id].bytes;
192                 last_time = timeval_current();
193                 return;
194         }
195
196         tdelay = (children[nbio_id].bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
197         if (tdelay > 0) {
198                 msleep(tdelay*1000);
199         } else {
200                 children[nbio_id].max_latency = MAX(children[nbio_id].max_latency, -tdelay);
201         }
202
203         last_time = timeval_current();
204         last_bytes = children[nbio_id].bytes;
205 }
206
207 void nbio_time_reset(void)
208 {
209         children[nbio_id].starttime = timeval_current();        
210 }
211
212 void nbio_time_delay(double targett)
213 {
214         double elapsed = timeval_elapsed(&children[nbio_id].starttime);
215         if (targett > elapsed) {
216                 msleep(1000*(targett - elapsed));
217         } else if (elapsed - targett > children[nbio_id].max_latency) {
218                 children[nbio_id].max_latency = MAX(elapsed - targett, children[nbio_id].max_latency);
219         }
220 }
221
222 double nbio_result(void)
223 {
224         int i;
225         double total = 0;
226         for (i=0;i<nprocs;i++) {
227                 total += children[i].bytes - children[i].warmup_bytes;
228         }
229         return 1.0e-6 * total / timeval_elapsed2(&tv_start, &tv_end);
230 }
231
232 double nbio_latency(void)
233 {
234         int i;
235         double max_latency = 0;
236         for (i=0;i<nprocs;i++) {
237                 if (children[i].max_latency > max_latency) {
238                         max_latency = children[i].max_latency;
239                         children[i].max_latency = 0;
240                 }
241         }
242         return max_latency;
243 }
244
245 BOOL nb_tick(void)
246 {
247         return children[nbio_id].done;
248 }
249
250
251 void nb_alarm(int sig)
252 {
253         int i;
254         int lines=0;
255         double t;
256         int in_warmup = 0;
257         int num_connected = 0;
258
259         if (nbio_id != -1) return;
260
261         for (i=0;i<nprocs;i++) {
262                 if (children[i].connected) {
263                         num_connected++;
264                 }
265                 if (children[i].bytes == 0) {
266                         in_warmup = 1;
267                 }
268                 lines += children[i].line;
269         }
270
271         t = timeval_elapsed(&tv_start);
272
273         if (!in_warmup && warmup>0 && t > warmup) {
274                 tv_start = timeval_current();
275                 warmup = 0;
276                 for (i=0;i<nprocs;i++) {
277                         children[i].warmup_bytes = children[i].bytes;
278                 }
279                 goto next;
280         }
281         if (t < warmup) {
282                 in_warmup = 1;
283         } else if (!in_warmup && !in_cleanup && t > timelimit) {
284                 for (i=0;i<nprocs;i++) {
285                         children[i].done = 1;
286                 }
287                 tv_end = timeval_current();
288                 in_cleanup = 1;
289         }
290         if (t < 1) {
291                 goto next;
292         }
293         if (!in_cleanup) {
294                 tv_end = timeval_current();
295         }
296
297         if (in_warmup) {
298                 printf("%4d  %8d  %.2f MB/sec  warmup %.0f sec   \n", 
299                        num_connected, lines/nprocs, 
300                        nbio_result(), t);
301         } else if (in_cleanup) {
302                 printf("%4d  %8d  %.2f MB/sec  cleanup %.0f sec   \n", 
303                        num_connected, lines/nprocs, 
304                        nbio_result(), t);
305         } else {
306                 printf("%4d  %8d  %.2f MB/sec  execute %.0f sec  latency %.2f msec \n", 
307                        num_connected, lines/nprocs, 
308                        nbio_result(), t, nbio_latency() * 1.0e3);
309         }
310
311         fflush(stdout);
312 next:
313         signal(SIGALRM, nb_alarm);
314         alarm(1);       
315 }
316
317 void nbio_shmem(int n, int t_timelimit, int t_warmup)
318 {
319         nprocs = n;
320         children = shm_setup(sizeof(*children) * nprocs);
321         if (!children) {
322                 printf("Failed to setup shared memory!\n");
323                 nb_exit(1);
324         }
325         memset(children, 0, sizeof(*children) * nprocs);
326         timelimit = t_timelimit;
327         warmup = t_warmup;
328         in_cleanup = 0;
329         tv_start = timeval_current();
330 }
331
332 static struct lock_info* find_lock(struct lock_info *linfo, off_t offset, int size)
333 {
334         while (linfo != NULL) {
335                 if (linfo->offset == offset &&
336                     linfo->size == size)
337                 {
338                         return linfo;
339                 }
340
341                 linfo = linfo->next;
342         }
343
344         return NULL;
345 }
346
347 static struct ftable *find_ftable(int handle)
348 {
349         struct ftable *f;
350
351         for (f=ftable;f;f=f->next) {
352                 if (f->handle == handle) return f;
353         }
354         return NULL;
355 }
356
357 static int find_handle(int handle, struct ftable **f_ret)
358 {
359         struct ftable *f;
360
361         if (f_ret != NULL)
362                 *f_ret = NULL;
363
364         children[nbio_id].line = nbench_line_count;
365
366         f = find_ftable(handle);
367         if (f) {
368                 if (f_ret != NULL)
369                         *f_ret = f;
370                 return f->fd;
371         }
372         printf("(%d) ERROR: handle %d was not found\n", 
373                nbench_line_count, handle);
374         nb_exit(1);
375
376         return -1;              /* Not reached */
377 }
378
379
380
381 static struct smbcli_state *c;
382
383 /*
384   a handler function for oplock break requests
385 */
386 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, 
387                            uint16_t fnum, uint8_t level, void *private)
388 {
389         struct smbcli_tree *tree = (struct smbcli_tree *)private;
390         return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
391 }
392
393 void nb_setup(struct smbcli_state *cli, int id)
394 {
395         nbio_id = id;
396         c = cli;
397         if (bypass_io)
398                 printf("skipping I/O\n");
399
400         if (cli) {
401                 smbcli_oplock_handler(cli->transport, oplock_handler, cli->tree);
402         }
403
404         children[id].connected = true;
405 }
406
407
408 static bool check_status(const char *op, NTSTATUS status, NTSTATUS ret)
409 {
410         if ((NT_STATUS_EQUAL(ret, NT_STATUS_END_OF_FILE) ||
411              NT_STATUS_EQUAL(ret, NT_STATUS_NET_WRITE_FAULT) ||
412              NT_STATUS_EQUAL(ret, NT_STATUS_CONNECTION_RESET)) 
413                 && !NT_STATUS_EQUAL (status, ret))
414         {
415                 return False;
416         }
417
418         if (!NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(ret)) {
419                 printf("[%d] Error: %s should have failed with %s\n", 
420                        nbench_line_count, op, nt_errstr(status));
421                 nb_exit(1);
422         }
423
424         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ret)) {
425                 printf("[%d] Error: %s should have succeeded - %s\n", 
426                        nbench_line_count, op, nt_errstr(ret));
427                 nb_exit(1);
428         }
429
430         if (!NT_STATUS_EQUAL(status, ret)) {
431                 printf("[%d] Warning: got status %s but expected %s\n",
432                        nbench_line_count, nt_errstr(ret), nt_errstr(status));
433         }
434
435         return True;
436 }
437
438
439 bool nb_unlink(const char *fname, int attr, NTSTATUS status, bool retry)
440 {
441         union smb_unlink io;
442         NTSTATUS ret;
443
444         io.unlink.in.pattern = fname;
445
446         io.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
447         if (strchr(fname, '*') == 0) {
448                 io.unlink.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
449         }
450
451         ret = smb_raw_unlink(c->tree, &io);
452
453         if (!retry)
454                 return check_status("Unlink", status, ret);
455
456         return True;
457 }
458
459 static bool nb_do_createx(struct ftable *f,
460                           const char *fname,
461                           uint_t create_options,
462                           uint_t create_disposition,
463                           int handle,
464                           NTSTATUS status,
465                           bool retry)
466 {
467         union smb_open io;      
468         uint32_t desired_access;
469         NTSTATUS ret;
470         TALLOC_CTX *mem_ctx;
471         uint_t flags = 0;
472
473         mem_ctx = talloc_init("raw_open");
474
475         if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
476                 desired_access = SEC_FILE_READ_DATA;
477         } else {
478                 desired_access = 
479                         SEC_FILE_READ_DATA | 
480                         SEC_FILE_WRITE_DATA |
481                         SEC_FILE_READ_ATTRIBUTE |
482                         SEC_FILE_WRITE_ATTRIBUTE;
483                 flags = NTCREATEX_FLAGS_EXTENDED |
484                         NTCREATEX_FLAGS_REQUEST_OPLOCK | 
485                         NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
486         }
487
488         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
489         io.ntcreatex.in.flags = flags;
490         io.ntcreatex.in.root_fid = 0;
491         io.ntcreatex.in.access_mask = desired_access;
492         io.ntcreatex.in.file_attr = 0;
493         io.ntcreatex.in.alloc_size = 0;
494         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE;
495         io.ntcreatex.in.open_disposition = create_disposition;
496         io.ntcreatex.in.create_options = create_options;
497         io.ntcreatex.in.impersonation = 0;
498         io.ntcreatex.in.security_flags = 0;
499         io.ntcreatex.in.fname = fname;
500
501         if (retry) {
502                 /* Reopening after a disconnect. */
503                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
504         } else
505         if (f != NULL &&
506             f->cp.create_disposition == NTCREATEX_DISP_CREATE &&
507             NT_STATUS_IS_OK(status))
508         {
509                 /* Reopening after nb_createx() error. */
510                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
511         }
512
513         ret = smb_raw_open(c->tree, mem_ctx, &io);
514
515         talloc_free(mem_ctx);
516
517         if (!check_status("NTCreateX", status, ret))
518                 return False;
519
520         if (!NT_STATUS_IS_OK(ret))
521                 return True;
522
523         if (f == NULL) {
524                 f = talloc (NULL, struct ftable);
525                 f->locks = NULL;
526                 nb_set_createx_params(f, fname, create_options, create_disposition, handle);
527                 DLIST_ADD_END(ftable, f, struct ftable *);
528         }
529
530         f->handle = handle;
531         f->fd = io.ntcreatex.out.file.fnum;
532
533         return True;
534 }
535
536 bool nb_createx(const char *fname, 
537                uint_t create_options, uint_t create_disposition, int handle,
538                NTSTATUS status)
539 {
540         return nb_do_createx(NULL, fname, create_options, create_disposition, handle, status, False);
541 }
542
543 bool nb_writex(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
544 {
545         union smb_write io;
546         int i;
547         NTSTATUS ret;
548         uint8_t *buf;
549
550         i = find_handle(handle, NULL);
551
552         if (bypass_io)
553                 return True;
554
555         buf = malloc(size);
556         memset(buf, 0xab, size);
557
558         io.writex.level = RAW_WRITE_WRITEX;
559         io.writex.in.file.fnum = i;
560         io.writex.in.wmode = 0;
561         io.writex.in.remaining = 0;
562         io.writex.in.offset = offset;
563         io.writex.in.count = size;
564         io.writex.in.data = buf;
565
566         ret = smb_raw_write(c->tree, &io);
567
568         free(buf);
569
570         if (!check_status("WriteX", status, ret))
571                 return False;
572
573         if (NT_STATUS_IS_OK(ret) && io.writex.out.nwritten != ret_size) {
574                 printf("[%d] Warning: WriteX got count %d expected %d\n", 
575                        nbench_line_count,
576                        io.writex.out.nwritten, ret_size);
577         }       
578
579         children[nbio_id].bytes += ret_size;
580
581         return True;
582 }
583
584 bool nb_write(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
585 {
586         union smb_write io;
587         int i;
588         NTSTATUS ret;
589         uint8_t *buf;
590
591         i = find_handle(handle, NULL);
592
593         if (bypass_io)
594                 return True;
595
596         buf = malloc(size);
597
598         memset(buf, 0x12, size);
599
600         io.write.level = RAW_WRITE_WRITE;
601         io.write.in.file.fnum = i;
602         io.write.in.remaining = 0;
603         io.write.in.offset = offset;
604         io.write.in.count = size;
605         io.write.in.data = buf;
606
607         ret = smb_raw_write(c->tree, &io);
608
609         free(buf);
610
611         if (!check_status("Write", status, ret))
612                 return False;
613
614         if (NT_STATUS_IS_OK(ret) && io.write.out.nwritten != ret_size) {
615                 printf("[%d] Warning: Write got count %d expected %d\n", 
616                        nbench_line_count,
617                        io.write.out.nwritten, ret_size);
618         }       
619
620         children[nbio_id].bytes += ret_size;
621
622         return True;
623 }
624
625 static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status)
626 {
627         union smb_lock io;
628         int i;
629         NTSTATUS ret;
630         struct smb_lock_entry lck;
631         struct ftable *f;
632
633         i = find_handle(handle, &f);
634
635         lck.pid = getpid();
636         lck.offset = offset;
637         lck.count = size;
638
639         io.lockx.level = RAW_LOCK_LOCKX;
640         io.lockx.in.file.fnum = i;
641         io.lockx.in.mode = 0;
642         io.lockx.in.timeout = 0;
643         io.lockx.in.ulock_cnt = 0;
644         io.lockx.in.lock_cnt = 1;
645         io.lockx.in.locks = &lck;
646
647         ret = smb_raw_lock(c->tree, &io);
648
649         if (!check_status("LockX", status, ret))
650                 return False;
651
652         if (f != NULL &&
653             !relock)
654         {
655                 struct lock_info *linfo;
656                 linfo = talloc (f, struct lock_info);
657                 linfo->offset = offset;
658                 linfo->size = size;
659                 DLIST_ADD_END(f->locks, linfo, struct lock_info *);
660         }
661
662         return True;
663 }
664
665 bool nb_lockx(int handle, off_t offset, int size, NTSTATUS status)
666 {
667         return nb_do_lockx(false, handle, offset, size, status);
668 }
669
670 bool nb_unlockx(int handle, uint_t offset, int size, NTSTATUS status)
671 {
672         union smb_lock io;
673         int i;
674         NTSTATUS ret;
675         struct smb_lock_entry lck;
676         struct ftable *f;
677
678         i = find_handle(handle, &f);
679
680         lck.pid = getpid();
681         lck.offset = offset;
682         lck.count = size;
683
684         io.lockx.level = RAW_LOCK_LOCKX;
685         io.lockx.in.file.fnum = i;
686         io.lockx.in.mode = 0;
687         io.lockx.in.timeout = 0;
688         io.lockx.in.ulock_cnt = 1;
689         io.lockx.in.lock_cnt = 0;
690         io.lockx.in.locks = &lck;
691
692         ret = smb_raw_lock(c->tree, &io);
693
694         if (!check_status("UnlockX", status, ret))
695                 return False;
696
697         if (f != NULL) {
698                 struct lock_info *linfo;
699                 linfo = find_lock(f->locks, offset, size);
700                 if (linfo != NULL)
701                         DLIST_REMOVE(f->locks, linfo);
702                 else
703                         printf("nb_unlockx: unknown lock (%d)\n", handle);
704         }
705
706         return True;
707 }
708
709 bool nb_readx(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
710 {
711         union smb_read io;
712         int i;
713         NTSTATUS ret;
714         uint8_t *buf;
715
716         i = find_handle(handle, NULL);
717
718         if (bypass_io)
719                 return True;
720
721         buf = malloc(size);
722
723         io.readx.level = RAW_READ_READX;
724         io.readx.in.file.fnum = i;
725         io.readx.in.offset    = offset;
726         io.readx.in.mincnt    = size;
727         io.readx.in.maxcnt    = size;
728         io.readx.in.remaining = 0;
729         io.readx.in.read_for_execute = False;
730         io.readx.out.data     = buf;
731
732         ret = smb_raw_read(c->tree, &io);
733
734         free(buf);
735
736         if (!check_status("ReadX", status, ret))
737                 return False;
738
739         if (NT_STATUS_IS_OK(ret) && io.readx.out.nread != ret_size) {
740                 printf("[%d] ERROR: ReadX got count %d expected %d\n", 
741                        nbench_line_count,
742                        io.readx.out.nread, ret_size);
743                 nb_exit(1);
744         }       
745
746         children[nbio_id].bytes += ret_size;
747
748         return True;
749 }
750
751 bool nb_close(int handle, NTSTATUS status)
752 {
753         NTSTATUS ret;
754         union smb_close io;
755         int i;
756
757         i = find_handle(handle, NULL);
758
759         io.close.level = RAW_CLOSE_CLOSE;
760         io.close.in.file.fnum = i;
761         io.close.in.write_time = 0;
762
763         ret = smb_raw_close(c->tree, &io);
764
765         if (!check_status("Close", status, ret))
766                 return False;
767
768         if (NT_STATUS_IS_OK(ret)) {
769                 struct ftable *f = find_ftable(handle);
770                 DLIST_REMOVE(ftable, f);
771                 talloc_free(f);
772         }
773
774         return True;
775 }
776
777 bool nb_rmdir(const char *dname, NTSTATUS status, bool retry)
778 {
779         NTSTATUS ret;
780         struct smb_rmdir io;
781
782         io.in.path = dname;
783
784         ret = smb_raw_rmdir(c->tree, &io);
785
786         if (!retry)
787                 return check_status("Rmdir", status, ret);
788
789         return True;
790 }
791
792 bool nb_mkdir(const char *dname, NTSTATUS status, bool retry)
793 {
794         union smb_mkdir io;
795
796         io.mkdir.level = RAW_MKDIR_MKDIR;
797         io.mkdir.in.path = dname;
798
799         /* NOTE! no error checking. Used for base fileset creation */
800         smb_raw_mkdir(c->tree, &io);
801
802         return True;
803 }
804
805 bool nb_rename(const char *old, const char *new, NTSTATUS status, bool retry)
806 {
807         NTSTATUS ret;
808         union smb_rename io;
809
810         io.generic.level = RAW_RENAME_RENAME;
811         io.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
812         io.rename.in.pattern1 = old;
813         io.rename.in.pattern2 = new;
814
815         ret = smb_raw_rename(c->tree, &io);
816
817         if (!retry)
818                 return check_status("Rename", status, ret);
819
820         return True;
821 }
822
823
824 bool nb_qpathinfo(const char *fname, int level, NTSTATUS status)
825 {
826         union smb_fileinfo io;
827         TALLOC_CTX *mem_ctx;
828         NTSTATUS ret;
829
830         mem_ctx = talloc_init("nb_qpathinfo");
831
832         io.generic.level = level;
833         io.generic.in.file.path = fname;
834
835         ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
836
837         talloc_free(mem_ctx);
838
839         return check_status("Pathinfo", status, ret);
840 }
841
842
843 bool nb_qfileinfo(int fnum, int level, NTSTATUS status)
844 {
845         union smb_fileinfo io;
846         TALLOC_CTX *mem_ctx;
847         NTSTATUS ret;
848         int i;
849
850         i = find_handle(fnum, NULL);
851
852         mem_ctx = talloc_init("nb_qfileinfo");
853
854         io.generic.level = level;
855         io.generic.in.file.fnum = i;
856
857         ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
858
859         talloc_free(mem_ctx);
860
861         return check_status("Fileinfo", status, ret);
862 }
863
864 bool nb_sfileinfo(int fnum, int level, NTSTATUS status)
865 {
866         union smb_setfileinfo io;
867         NTSTATUS ret;
868         int i;
869
870         if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
871                 printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
872                 return True;
873         }
874
875         ZERO_STRUCT(io);
876
877         i = find_handle(fnum, NULL);
878
879         io.generic.level = level;
880         io.generic.in.file.fnum = i;
881         unix_to_nt_time(&io.basic_info.in.create_time, time(NULL));
882         unix_to_nt_time(&io.basic_info.in.access_time, 0);
883         unix_to_nt_time(&io.basic_info.in.write_time, 0);
884         unix_to_nt_time(&io.basic_info.in.change_time, 0);
885         io.basic_info.in.attrib = 0;
886
887         ret = smb_raw_setfileinfo(c->tree, &io);
888
889         return check_status("Setfileinfo", status, ret);
890 }
891
892 bool nb_qfsinfo(int level, NTSTATUS status)
893 {
894         union smb_fsinfo io;
895         TALLOC_CTX *mem_ctx;
896         NTSTATUS ret;
897
898         mem_ctx = talloc_init("smbcli_dskattr");
899
900         io.generic.level = level;
901         ret = smb_raw_fsinfo(c->tree, mem_ctx, &io);
902
903         talloc_free(mem_ctx);
904         
905         return check_status("Fsinfo", status, ret);     
906 }
907
908 /* callback function used for trans2 search */
909 static BOOL findfirst_callback(void *private, const union smb_search_data *file)
910 {
911         return True;
912 }
913
914 bool nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
915 {
916         union smb_search_first io;
917         TALLOC_CTX *mem_ctx;
918         NTSTATUS ret;
919
920         mem_ctx = talloc_init("smbcli_dskattr");
921
922         io.t2ffirst.level = RAW_SEARCH_TRANS2;
923         io.t2ffirst.data_level = level;
924         io.t2ffirst.in.max_count = maxcnt;
925         io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
926         io.t2ffirst.in.pattern = mask;
927         io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
928         io.t2ffirst.in.storage_type = 0;
929                         
930         ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback);
931
932         talloc_free(mem_ctx);
933
934         if (!check_status("Search", status, ret))
935                 return False;
936
937         if (NT_STATUS_IS_OK(ret) && io.t2ffirst.out.count != count) {
938                 printf("[%d] Warning: got count %d expected %d\n", 
939                        nbench_line_count,
940                        io.t2ffirst.out.count, count);
941         }
942
943         return True;
944 }
945
946 bool nb_flush(int fnum, NTSTATUS status)
947 {
948         union smb_flush io;
949         NTSTATUS ret;
950         int i;
951         i = find_handle(fnum, NULL);
952
953         io.flush.level          = RAW_FLUSH_FLUSH;
954         io.flush.in.file.fnum   = i;
955
956         ret = smb_raw_flush(c->tree, &io);
957
958         return check_status("Flush", status, ret);
959 }
960
961 void nb_sleep(int usec, NTSTATUS status)
962 {
963         usleep(usec);
964 }
965
966 bool nb_deltree(const char *dname, bool retry)
967 {
968         int total_deleted;
969
970         smb_raw_exit(c->session);
971
972         while (ftable) {
973                 struct ftable *f = ftable;
974                 DLIST_REMOVE(ftable, f);
975                 talloc_free (f);
976         }
977
978         total_deleted = smbcli_deltree(c->tree, dname);
979
980         if (total_deleted == -1) {
981                 printf("Failed to cleanup tree %s - exiting\n", dname);
982                 nb_exit(1);
983         }
984
985         smbcli_rmdir(c->tree, dname);
986
987         return True;
988 }
989
990
991 void nb_exit(int status)
992 {
993         children[nbio_id].connected = false;
994         printf("[%d] client %d exiting with status %d\n",
995                nbench_line_count, nbio_id, status);
996         exit(status);
997 }