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