r16907: Add an index parameter to torture_open_connection. Next step is to enable the
[gd/samba-autobuild/.git] / source4 / torture / raw / oplock.c
1 /* 
2    Unix SMB/CIFS implementation.
3    basic raw test suite for oplocks
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "librpc/gen_ndr/security.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "lib/events/events.h"
28
29 #define CHECK_VAL(v, correct) do { \
30         if ((v) != (correct)) { \
31                 printf("(%d) wrong value for %s  got 0x%x - should be 0x%x\n", \
32                        __LINE__, #v, (int)v, (int)correct); \
33                 ret = False; \
34         }} while (0)
35
36 #define CHECK_STATUS(status, correct) do { \
37         if (!NT_STATUS_EQUAL(status, correct)) { \
38                 printf("(%d) Incorrect status %s - should be %s\n", \
39                        __LINE__, nt_errstr(status), nt_errstr(correct)); \
40                 ret = False; \
41                 goto done; \
42         }} while (0)
43
44
45 static struct {
46         int fnum;
47         uint8_t level;
48         int count;
49         int failures;
50 } break_info;
51
52 #define BASEDIR "\\test_notify"
53
54 /*
55   a handler function for oplock break requests. Ack it as a break to level II if possible
56 */
57 static BOOL oplock_handler_ack_to_levelII(struct smbcli_transport *transport, uint16_t tid, 
58                                uint16_t fnum, uint8_t level, void *private)
59 {
60         struct smbcli_tree *tree = private;
61         break_info.fnum = fnum;
62         break_info.level = level;
63         break_info.count++;
64
65         printf("Acking to level II in oplock handler\n");
66
67         return smbcli_oplock_ack(tree, fnum, level);
68 }
69
70 /*
71   a handler function for oplock break requests. Ack it as a break to none
72 */
73 static BOOL oplock_handler_ack_to_none(struct smbcli_transport *transport, uint16_t tid, 
74                                     uint16_t fnum, uint8_t level, 
75                                     void *private)
76 {
77         struct smbcli_tree *tree = private;
78         break_info.fnum = fnum;
79         break_info.level = level;
80         break_info.count++;
81
82         printf("Acking to none in oplock handler\n");
83
84         return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
85 }
86
87 static void oplock_handler_close_recv(struct smbcli_request *req)
88 {
89         NTSTATUS status;
90         status = smbcli_request_simple_recv(req);
91         if (!NT_STATUS_IS_OK(status)) {
92                 printf("close failed in oplock_handler_close\n");
93                 break_info.failures++;
94         }
95 }
96
97 /*
98   a handler function for oplock break requests - close the file
99 */
100 static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid, 
101                                  uint16_t fnum, uint8_t level, void *private)
102 {
103         union smb_close io;
104         struct smbcli_tree *tree = private;
105         struct smbcli_request *req;
106
107         break_info.fnum = fnum;
108         break_info.level = level;
109         break_info.count++;
110
111         io.close.level = RAW_CLOSE_CLOSE;
112         io.close.in.file.fnum = fnum;
113         io.close.in.write_time = 0;
114         req = smb_raw_close_send(tree, &io);
115         if (req == NULL) {
116                 printf("failed to send close in oplock_handler_close\n");
117                 return False;
118         }
119
120         req->async.fn = oplock_handler_close_recv;
121         req->async.private = NULL;
122
123         return True;
124 }
125
126 /*
127   test oplock ops
128 */
129 static BOOL test_oplock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
130 {
131         const char *fname = BASEDIR "\\test_oplock.dat";
132         NTSTATUS status;
133         BOOL ret = True;
134         union smb_open io;
135         union smb_unlink unl;
136         union smb_read rd;
137         union smb_setfileinfo sfi;
138         uint16_t fnum=0, fnum2=0;
139         char c = 0;
140
141         /* cleanup */
142         smbcli_unlink(cli->tree, fname);
143
144         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
145
146         /*
147           base ntcreatex parms
148         */
149         io.generic.level = RAW_OPEN_NTCREATEX;
150         io.ntcreatex.in.root_fid = 0;
151         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
152         io.ntcreatex.in.alloc_size = 0;
153         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
154         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
155         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
156         io.ntcreatex.in.create_options = 0;
157         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
158         io.ntcreatex.in.security_flags = 0;
159         io.ntcreatex.in.fname = fname;
160
161         printf("open a file with a normal oplock\n");
162         ZERO_STRUCT(break_info);
163         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
164
165         status = smb_raw_open(cli->tree, mem_ctx, &io);
166         CHECK_STATUS(status, NT_STATUS_OK);
167         fnum = io.ntcreatex.out.file.fnum;
168         CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
169
170         printf("a 2nd open should not cause a break\n");
171         status = smb_raw_open(cli->tree, mem_ctx, &io);
172         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
173         CHECK_VAL(break_info.count, 0);
174         CHECK_VAL(break_info.failures, 0);
175
176         printf("unlink it - should also be no break\n");
177         unl.unlink.in.pattern = fname;
178         unl.unlink.in.attrib = 0;
179         status = smb_raw_unlink(cli->tree, &unl);
180         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
181         CHECK_VAL(break_info.count, 0);
182         CHECK_VAL(break_info.failures, 0);
183
184         smbcli_close(cli->tree, fnum);
185
186         /*
187           with a batch oplock we get a break
188         */
189         printf("open with batch oplock\n");
190         ZERO_STRUCT(break_info);
191         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
192                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
193                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
194         status = smb_raw_open(cli->tree, mem_ctx, &io);
195         CHECK_STATUS(status, NT_STATUS_OK);
196         fnum = io.ntcreatex.out.file.fnum;
197         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
198
199         printf("unlink should generate a break\n");
200         unl.unlink.in.pattern = fname;
201         unl.unlink.in.attrib = 0;
202         status = smb_raw_unlink(cli->tree, &unl);
203         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
204
205         CHECK_VAL(break_info.count, 1);
206         CHECK_VAL(break_info.fnum, fnum);
207         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
208         CHECK_VAL(break_info.failures, 0);
209
210         printf("2nd unlink should not generate a break\n");
211         ZERO_STRUCT(break_info);
212         status = smb_raw_unlink(cli->tree, &unl);
213         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
214
215         CHECK_VAL(break_info.count, 0);
216
217         printf("writing should generate a self break to none\n");
218         smbcli_write(cli->tree, fnum, 0, &c, 0, 1);
219         msleep(100);
220         smbcli_write(cli->tree, fnum, 0, &c, 1, 1);
221
222         CHECK_VAL(break_info.count, 1);
223         CHECK_VAL(break_info.fnum, fnum);
224         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
225         CHECK_VAL(break_info.failures, 0);
226
227         smbcli_close(cli->tree, fnum);
228
229
230         printf("open with batch oplock\n");
231         ZERO_STRUCT(break_info);
232         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
233                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
234                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
235         status = smb_raw_open(cli->tree, mem_ctx, &io);
236         CHECK_STATUS(status, NT_STATUS_OK);
237         fnum = io.ntcreatex.out.file.fnum;
238         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
239
240         printf("unlink should generate a break, which we ack as break to none\n");
241         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_none, cli->tree);
242         unl.unlink.in.pattern = fname;
243         unl.unlink.in.attrib = 0;
244         status = smb_raw_unlink(cli->tree, &unl);
245         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
246
247         CHECK_VAL(break_info.count, 1);
248         CHECK_VAL(break_info.fnum, fnum);
249         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
250         CHECK_VAL(break_info.failures, 0);
251
252         printf("2nd unlink should not generate a break\n");
253         ZERO_STRUCT(break_info);
254         status = smb_raw_unlink(cli->tree, &unl);
255         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
256
257         CHECK_VAL(break_info.count, 0);
258
259         printf("writing should not generate a break\n");
260         smbcli_write(cli->tree, fnum, 0, &c, 0, 1);
261         msleep(100);
262         smbcli_write(cli->tree, fnum, 0, &c, 1, 1);
263
264         CHECK_VAL(break_info.count, 0);
265
266         smbcli_close(cli->tree, fnum);
267
268         printf("if we close on break then the unlink can succeed\n");
269         ZERO_STRUCT(break_info);
270         smbcli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
271         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
272                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
273                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
274         status = smb_raw_open(cli->tree, mem_ctx, &io);
275         CHECK_STATUS(status, NT_STATUS_OK);
276         fnum = io.ntcreatex.out.file.fnum;
277         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
278
279         unl.unlink.in.pattern = fname;
280         unl.unlink.in.attrib = 0;
281         ZERO_STRUCT(break_info);
282         status = smb_raw_unlink(cli->tree, &unl);
283         CHECK_STATUS(status, NT_STATUS_OK);
284
285         CHECK_VAL(break_info.count, 1);
286         CHECK_VAL(break_info.fnum, fnum);
287         CHECK_VAL(break_info.level, 1);
288         CHECK_VAL(break_info.failures, 0);
289
290         printf("a self read should not cause a break\n");
291         ZERO_STRUCT(break_info);
292         smbcli_close(cli->tree, fnum);
293         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
294
295         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
296                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
297                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
298         status = smb_raw_open(cli->tree, mem_ctx, &io);
299         CHECK_STATUS(status, NT_STATUS_OK);
300         fnum = io.ntcreatex.out.file.fnum;
301         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
302
303         rd.read.level = RAW_READ_READ;
304         rd.read.in.file.fnum = fnum;
305         rd.read.in.count = 1;
306         rd.read.in.offset = 0;
307         rd.read.in.remaining = 0;
308         status = smb_raw_read(cli->tree, &rd);
309         CHECK_STATUS(status, NT_STATUS_OK);
310         CHECK_VAL(break_info.count, 0);
311         CHECK_VAL(break_info.failures, 0);
312
313         printf("a 2nd open should give a break\n");
314         ZERO_STRUCT(break_info);
315         smbcli_close(cli->tree, fnum);
316         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
317
318         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
319                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
320                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
321         status = smb_raw_open(cli->tree, mem_ctx, &io);
322         CHECK_STATUS(status, NT_STATUS_OK);
323         fnum = io.ntcreatex.out.file.fnum;
324         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
325
326         ZERO_STRUCT(break_info);
327
328         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
329         status = smb_raw_open(cli->tree, mem_ctx, &io);
330         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
331
332         CHECK_VAL(break_info.count, 1);
333         CHECK_VAL(break_info.fnum, fnum);
334         CHECK_VAL(break_info.level, 1);
335         CHECK_VAL(break_info.failures, 0);
336
337
338         printf("a 2nd open should give a break to level II if the first open allowed shared read\n");
339         ZERO_STRUCT(break_info);
340         smbcli_close(cli->tree, fnum);
341         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
342
343         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
344         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
345         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
346                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
347                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
348         status = smb_raw_open(cli->tree, mem_ctx, &io);
349         CHECK_STATUS(status, NT_STATUS_OK);
350         fnum = io.ntcreatex.out.file.fnum;
351         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
352
353         ZERO_STRUCT(break_info);
354
355         status = smb_raw_open(cli->tree, mem_ctx, &io);
356         CHECK_STATUS(status, NT_STATUS_OK);
357         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
358
359         CHECK_VAL(break_info.count, 1);
360         CHECK_VAL(break_info.fnum, fnum);
361         CHECK_VAL(break_info.level, 1);
362         CHECK_VAL(break_info.failures, 0);
363         ZERO_STRUCT(break_info);
364
365         printf("write should trigger a break to none on both\n");
366         smbcli_write(cli->tree, fnum, 0, &c, 0, 1);
367         msleep(100);
368         smbcli_write(cli->tree, fnum, 0, &c, 1, 1);
369
370         CHECK_VAL(break_info.count, 2);
371         CHECK_VAL(break_info.level, 0);
372         CHECK_VAL(break_info.failures, 0);
373
374         smb_raw_exit(cli->session);
375
376         printf("a 2nd open should get an oplock when we close instead of ack\n");
377         ZERO_STRUCT(break_info);
378         smbcli_close(cli->tree, fnum);
379         smbcli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
380
381         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
382         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
383         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
384                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
385                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
386         status = smb_raw_open(cli->tree, mem_ctx, &io);
387         CHECK_STATUS(status, NT_STATUS_OK);
388         fnum2 = io.ntcreatex.out.file.fnum;
389         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
390
391         ZERO_STRUCT(break_info);
392
393         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
394                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
395                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
396         status = smb_raw_open(cli->tree, mem_ctx, &io);
397         CHECK_STATUS(status, NT_STATUS_OK);
398         fnum = io.ntcreatex.out.file.fnum;
399         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
400
401         CHECK_VAL(break_info.count, 1);
402         CHECK_VAL(break_info.fnum, fnum2);
403         CHECK_VAL(break_info.level, 1);
404         CHECK_VAL(break_info.failures, 0);
405         
406         smbcli_close(cli->tree, fnum);
407
408         printf("open with batch oplock\n");
409         ZERO_STRUCT(break_info);
410         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
411
412         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
413                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
414                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
415         status = smb_raw_open(cli->tree, mem_ctx, &io);
416         CHECK_STATUS(status, NT_STATUS_OK);
417         fnum = io.ntcreatex.out.file.fnum;
418         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
419
420         ZERO_STRUCT(break_info);
421         printf("second open with attributes only shouldn't cause oplock break\n");
422
423         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
424                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
425                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
426         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
427         status = smb_raw_open(cli->tree, mem_ctx, &io);
428         CHECK_STATUS(status, NT_STATUS_OK);
429         fnum2 = io.ntcreatex.out.file.fnum;
430         CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
431         CHECK_VAL(break_info.count, 0);
432         CHECK_VAL(break_info.failures, 0);
433
434         smbcli_close(cli->tree, fnum);
435         smbcli_close(cli->tree, fnum2);
436         smbcli_unlink(cli->tree, fname);
437
438         printf("open with attributes only can create file\n");
439         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
440                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
441                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
442         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
443         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
444         status = smb_raw_open(cli->tree, mem_ctx, &io);
445         CHECK_STATUS(status, NT_STATUS_OK);
446         fnum = io.ntcreatex.out.file.fnum;
447         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
448
449         printf("Subsequent normal open should break oplock on attribute only open to level II\n");
450
451         ZERO_STRUCT(break_info);
452         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
453
454         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
455                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
456                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
457         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
458         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
459         status = smb_raw_open(cli->tree, mem_ctx, &io);
460         CHECK_STATUS(status, NT_STATUS_OK);
461         fnum2 = io.ntcreatex.out.file.fnum;
462         CHECK_VAL(break_info.count, 1);
463         CHECK_VAL(break_info.fnum, fnum);
464         CHECK_VAL(break_info.failures, 0);
465         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
466         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
467         smbcli_close(cli->tree, fnum2);
468
469         printf("third oplocked open should grant level2 without break\n");
470         ZERO_STRUCT(break_info);
471         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
472         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
473                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
474                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
475         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
476         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
477         status = smb_raw_open(cli->tree, mem_ctx, &io);
478         CHECK_STATUS(status, NT_STATUS_OK);
479         fnum2 = io.ntcreatex.out.file.fnum;
480         CHECK_VAL(break_info.count, 0);
481         CHECK_VAL(break_info.failures, 0);
482         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
483
484         ZERO_STRUCT(break_info);
485
486         printf("write should trigger a break to none on both\n");
487         smbcli_write(cli->tree, fnum2, 0, &c, 0, 1);
488
489         /* Now the oplock break request comes in. But right now we can't
490          * answer it. Do another write */
491
492         msleep(100);
493         smbcli_write(cli->tree, fnum2, 0, &c, 1, 1);
494
495         CHECK_VAL(break_info.count, 2);
496         CHECK_VAL(break_info.level, 0);
497         CHECK_VAL(break_info.failures, 0);
498
499         smbcli_close(cli->tree, fnum);
500         smbcli_close(cli->tree, fnum2);
501
502         ZERO_STRUCT(break_info);
503         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
504
505         printf("Open with oplock after a on-oplock open should grant level2\n");
506         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
507         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
508         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
509                 NTCREATEX_SHARE_ACCESS_WRITE|
510                 NTCREATEX_SHARE_ACCESS_DELETE;
511         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
512         status = smb_raw_open(cli->tree, mem_ctx, &io);
513         CHECK_STATUS(status, NT_STATUS_OK);
514         fnum = io.ntcreatex.out.file.fnum;
515         CHECK_VAL(break_info.count, 0);
516         CHECK_VAL(break_info.failures, 0);
517         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
518
519         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
520                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
521                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
522         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
523         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
524                 NTCREATEX_SHARE_ACCESS_WRITE|
525                 NTCREATEX_SHARE_ACCESS_DELETE;
526         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
527         status = smb_raw_open(cli->tree, mem_ctx, &io);
528         CHECK_STATUS(status, NT_STATUS_OK);
529         fnum2 = io.ntcreatex.out.file.fnum;
530         CHECK_VAL(break_info.count, 0);
531         CHECK_VAL(break_info.failures, 0);
532         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
533
534         printf("write should trigger a break to none\n");
535         {
536                 union smb_write wr;
537                 wr.write.level = RAW_WRITE_WRITE;
538                 wr.write.in.file.fnum = fnum;
539                 wr.write.in.count = 1;
540                 wr.write.in.offset = 0;
541                 wr.write.in.remaining = 0;
542                 wr.write.in.data = (const uint8_t *)"x";
543                 status = smb_raw_write(cli->tree, &wr);
544                 CHECK_STATUS(status, NT_STATUS_OK);
545         }
546
547         /* Now the oplock break request comes in. But right now we can't
548          * answer it. Do another write */
549
550         msleep(100);
551         
552         {
553                 union smb_write wr;
554                 wr.write.level = RAW_WRITE_WRITE;
555                 wr.write.in.file.fnum = fnum;
556                 wr.write.in.count = 1;
557                 wr.write.in.offset = 0;
558                 wr.write.in.remaining = 0;
559                 wr.write.in.data = (const uint8_t *)"x";
560                 status = smb_raw_write(cli->tree, &wr);
561                 CHECK_STATUS(status, NT_STATUS_OK);
562         }
563
564         CHECK_VAL(break_info.count, 1);
565         CHECK_VAL(break_info.fnum, fnum2);
566         CHECK_VAL(break_info.level, 0);
567         CHECK_VAL(break_info.failures, 0);
568
569         smbcli_close(cli->tree, fnum);
570         smbcli_close(cli->tree, fnum2);
571         smbcli_unlink(cli->tree, fname);
572
573         /* Test if a set-eof on pathname breaks an exclusive oplock. */
574         printf("Test if setpathinfo set EOF breaks oplocks.\n");
575
576         ZERO_STRUCT(break_info);
577         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
578
579         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
580                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
581                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
582         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
583         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
584                 NTCREATEX_SHARE_ACCESS_WRITE|
585                 NTCREATEX_SHARE_ACCESS_DELETE;
586         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
587         status = smb_raw_open(cli->tree, mem_ctx, &io);
588         CHECK_STATUS(status, NT_STATUS_OK);
589         fnum = io.ntcreatex.out.file.fnum;
590         CHECK_VAL(break_info.count, 0);
591         CHECK_VAL(break_info.failures, 0);
592         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
593         
594         ZERO_STRUCT(sfi);
595         sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
596         sfi.generic.in.file.path = fname;
597         sfi.end_of_file_info.in.size = 100;
598
599         status = smb_raw_setpathinfo(cli->tree, &sfi);
600
601         CHECK_STATUS(status, NT_STATUS_OK);
602         CHECK_VAL(break_info.count, 1);
603         CHECK_VAL(break_info.failures, 0);
604         CHECK_VAL(break_info.level, 0);
605
606         smbcli_close(cli->tree, fnum);
607         smbcli_unlink(cli->tree, fname);
608
609         /* Test if a set-allocation size on pathname breaks an exclusive oplock. */
610         printf("Test if setpathinfo allocation size breaks oplocks.\n");
611
612         ZERO_STRUCT(break_info);
613         smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_levelII, cli->tree);
614
615         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
616                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
617                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
618         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
619         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
620                 NTCREATEX_SHARE_ACCESS_WRITE|
621                 NTCREATEX_SHARE_ACCESS_DELETE;
622         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
623         status = smb_raw_open(cli->tree, mem_ctx, &io);
624         CHECK_STATUS(status, NT_STATUS_OK);
625         fnum = io.ntcreatex.out.file.fnum;
626         CHECK_VAL(break_info.count, 0);
627         CHECK_VAL(break_info.failures, 0);
628         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
629         
630         ZERO_STRUCT(sfi);
631         sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
632         sfi.generic.in.file.path = fname;
633         sfi.allocation_info.in.alloc_size = 65536 * 8;
634
635         status = smb_raw_setpathinfo(cli->tree, &sfi);
636
637         CHECK_STATUS(status, NT_STATUS_OK);
638         CHECK_VAL(break_info.count, 1);
639         CHECK_VAL(break_info.failures, 0);
640         CHECK_VAL(break_info.level, 0);
641
642 done:
643         smbcli_close(cli->tree, fnum);
644         smbcli_close(cli->tree, fnum2);
645         smbcli_unlink(cli->tree, fname);
646         return ret;
647 }
648
649
650 /* 
651    basic testing of oplocks
652 */
653 BOOL torture_raw_oplock(struct torture_context *torture)
654 {
655         struct smbcli_state *cli;
656         BOOL ret = True;
657         TALLOC_CTX *mem_ctx;
658
659         if (!torture_open_connection(&cli, 0)) {
660                 return False;
661         }
662
663         if (!torture_setup_dir(cli, BASEDIR)) {
664                 return False;
665         }
666
667         mem_ctx = talloc_init("torture_raw_oplock");
668
669         if (!test_oplock(cli, mem_ctx)) {
670                 ret = False;
671         }
672
673         smb_raw_exit(cli->session);
674         smbcli_deltree(cli->tree, BASEDIR);
675         torture_close_connection(cli);
676         talloc_free(mem_ctx);
677         return ret;
678 }
679
680
681 /* 
682    stress testing of oplocks
683 */
684 BOOL torture_bench_oplock(struct torture_context *torture)
685 {
686         struct smbcli_state **cli;
687         BOOL ret = True;
688         TALLOC_CTX *mem_ctx = talloc_new(torture);
689         extern int torture_nprocs;
690         int i, count=0;
691         int timelimit = lp_parm_int(-1, "torture", "timelimit", 10);
692         union smb_open io;
693         struct timeval tv;
694         struct event_context *ev = event_context_find(mem_ctx);
695
696         cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
697
698         printf("Opening %d connections\n", torture_nprocs);
699         for (i=0;i<torture_nprocs;i++) {
700                 if (!torture_open_connection_ev(&cli[i], ev)) {
701                         return False;
702                 }
703                 talloc_steal(mem_ctx, cli[i]);
704                 smbcli_oplock_handler(cli[i]->transport, oplock_handler_close, 
705                                       cli[i]->tree);
706         }
707
708         if (!torture_setup_dir(cli[0], BASEDIR)) {
709                 ret = False;
710                 goto done;
711         }
712
713         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
714         io.ntcreatex.in.root_fid = 0;
715         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
716         io.ntcreatex.in.alloc_size = 0;
717         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
718         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
719         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
720         io.ntcreatex.in.create_options = 0;
721         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
722         io.ntcreatex.in.security_flags = 0;
723         io.ntcreatex.in.fname = BASEDIR "\\test.dat";
724         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
725                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
726                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
727
728         tv = timeval_current(); 
729
730         /*
731           we open the same file with SHARE_ACCESS_NONE from all the
732           connections in a round robin fashion. Each open causes an
733           oplock break on the previous connection, which is answered
734           by the oplock_handler_close() to close the file.
735
736           This measures how fast we can pass on oplocks, and stresses
737           the oplock handling code
738         */
739         printf("Running for %d seconds\n", timelimit);
740         while (timeval_elapsed(&tv) < timelimit) {
741                 for (i=0;i<torture_nprocs;i++) {
742                         NTSTATUS status;
743
744                         status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
745                         CHECK_STATUS(status, NT_STATUS_OK);
746                         count++;
747                 }
748                 printf("%.2f ops/second\r", count/timeval_elapsed(&tv));
749         }
750
751         printf("%.2f ops/second\n", count/timeval_elapsed(&tv));
752
753         smb_raw_exit(cli[torture_nprocs-1]->session);
754         
755 done:
756         smb_raw_exit(cli[0]->session);
757         smbcli_deltree(cli[0]->tree, BASEDIR);
758         talloc_free(mem_ctx);
759         return ret;
760 }