r19392: Use torture_setting_* rather than lp_parm_* where possible.
[sfrench/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 *cli1, struct smbcli_state *cli2, 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(cli1->tree, fname);
143
144         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->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(cli1->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(cli2->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(cli2->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(cli1->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(cli1->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(cli2->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(cli2->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(cli1->tree, fnum, 0, &c, 0, 1);
219         msleep(100);
220         smbcli_write(cli1->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(cli1->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(cli1->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(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
242         unl.unlink.in.pattern = fname;
243         unl.unlink.in.attrib = 0;
244         status = smb_raw_unlink(cli2->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(cli2->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(cli1->tree, fnum, 0, &c, 0, 1);
261         msleep(100);
262         smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
263
264         CHECK_VAL(break_info.count, 0);
265
266         smbcli_close(cli1->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(cli1->transport, oplock_handler_close, cli1->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(cli1->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(cli2->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(cli1->tree, fnum);
293         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->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(cli1->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(cli1->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(cli1->tree, fnum);
316         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->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(cli1->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(cli2->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(cli1->tree, fnum);
341         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
342         smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
343
344         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
345         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
346         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
347                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
348                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
349         status = smb_raw_open(cli1->tree, mem_ctx, &io);
350         CHECK_STATUS(status, NT_STATUS_OK);
351         fnum = io.ntcreatex.out.file.fnum;
352         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
353
354         ZERO_STRUCT(break_info);
355
356         status = smb_raw_open(cli2->tree, mem_ctx, &io);
357         CHECK_STATUS(status, NT_STATUS_OK);
358         fnum2 = io.ntcreatex.out.file.fnum;
359         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
360
361         CHECK_VAL(break_info.count, 1);
362         CHECK_VAL(break_info.fnum, fnum);
363         CHECK_VAL(break_info.level, 1);
364         CHECK_VAL(break_info.failures, 0);
365         ZERO_STRUCT(break_info);
366
367         printf("write should trigger a break to none on both\n");
368         smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
369         msleep(100);
370         smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
371
372         CHECK_VAL(break_info.count, 2);
373         CHECK_VAL(break_info.level, 0);
374         CHECK_VAL(break_info.failures, 0);
375
376         smbcli_close(cli1->tree, fnum);
377         smbcli_close(cli2->tree, fnum2);
378
379         printf("a 2nd open should get an oplock when we close instead of ack\n");
380         ZERO_STRUCT(break_info);
381         smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
382
383         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
384         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
385         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
386                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
387                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
388         status = smb_raw_open(cli1->tree, mem_ctx, &io);
389         CHECK_STATUS(status, NT_STATUS_OK);
390         fnum2 = io.ntcreatex.out.file.fnum;
391         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
392
393         ZERO_STRUCT(break_info);
394
395         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
396                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
397                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
398         status = smb_raw_open(cli2->tree, mem_ctx, &io);
399         CHECK_STATUS(status, NT_STATUS_OK);
400         fnum = io.ntcreatex.out.file.fnum;
401         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
402
403         CHECK_VAL(break_info.count, 1);
404         CHECK_VAL(break_info.fnum, fnum2);
405         CHECK_VAL(break_info.level, 1);
406         CHECK_VAL(break_info.failures, 0);
407         
408         smbcli_close(cli2->tree, fnum);
409
410         printf("open with batch oplock\n");
411         ZERO_STRUCT(break_info);
412         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
413
414         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
415                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
416                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
417         status = smb_raw_open(cli1->tree, mem_ctx, &io);
418         CHECK_STATUS(status, NT_STATUS_OK);
419         fnum = io.ntcreatex.out.file.fnum;
420         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
421
422         ZERO_STRUCT(break_info);
423         printf("second open with attributes only shouldn't cause oplock break\n");
424
425         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
426                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
427                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
428         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
429         status = smb_raw_open(cli2->tree, mem_ctx, &io);
430         CHECK_STATUS(status, NT_STATUS_OK);
431         fnum2 = io.ntcreatex.out.file.fnum;
432         CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
433         CHECK_VAL(break_info.count, 0);
434         CHECK_VAL(break_info.failures, 0);
435
436         smbcli_close(cli1->tree, fnum);
437         smbcli_close(cli2->tree, fnum2);
438         smbcli_unlink(cli1->tree, fname);
439
440         printf("open with attributes only can create file\n");
441
442         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
443                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
444                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
445         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
446         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
447         status = smb_raw_open(cli1->tree, mem_ctx, &io);
448         CHECK_STATUS(status, NT_STATUS_OK);
449         fnum = io.ntcreatex.out.file.fnum;
450         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
451
452         printf("Subsequent normal open should break oplock on attribute only open to level II\n");
453
454         ZERO_STRUCT(break_info);
455         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
456
457         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
458                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
459                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
460         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
461         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
462         status = smb_raw_open(cli2->tree, mem_ctx, &io);
463         CHECK_STATUS(status, NT_STATUS_OK);
464         fnum2 = io.ntcreatex.out.file.fnum;
465         CHECK_VAL(break_info.count, 1);
466         CHECK_VAL(break_info.fnum, fnum);
467         CHECK_VAL(break_info.failures, 0);
468         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
469         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
470         smbcli_close(cli2->tree, fnum2);
471
472         printf("third oplocked open should grant level2 without break\n");
473         ZERO_STRUCT(break_info);
474         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
475         smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
476         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
477                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
478                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
479         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
480         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
481         status = smb_raw_open(cli2->tree, mem_ctx, &io);
482         CHECK_STATUS(status, NT_STATUS_OK);
483         fnum2 = io.ntcreatex.out.file.fnum;
484         CHECK_VAL(break_info.count, 0);
485         CHECK_VAL(break_info.failures, 0);
486         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
487
488         ZERO_STRUCT(break_info);
489
490         printf("write should trigger a break to none on both\n");
491         smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
492
493         /* Now the oplock break request comes in. But right now we can't
494          * answer it. Do another write */
495
496         msleep(100);
497         smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
498
499         CHECK_VAL(break_info.count, 2);
500         CHECK_VAL(break_info.level, 0);
501         CHECK_VAL(break_info.failures, 0);
502
503         smbcli_close(cli1->tree, fnum);
504         smbcli_close(cli2->tree, fnum2);
505
506         ZERO_STRUCT(break_info);
507         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
508
509         printf("Open with oplock after a on-oplock open should grant level2\n");
510         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
511         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
512         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
513                 NTCREATEX_SHARE_ACCESS_WRITE|
514                 NTCREATEX_SHARE_ACCESS_DELETE;
515         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
516         status = smb_raw_open(cli1->tree, mem_ctx, &io);
517         CHECK_STATUS(status, NT_STATUS_OK);
518         fnum = io.ntcreatex.out.file.fnum;
519         CHECK_VAL(break_info.count, 0);
520         CHECK_VAL(break_info.failures, 0);
521         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
522
523         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
524                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
525                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
526         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
527         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
528                 NTCREATEX_SHARE_ACCESS_WRITE|
529                 NTCREATEX_SHARE_ACCESS_DELETE;
530         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
531         status = smb_raw_open(cli2->tree, mem_ctx, &io);
532         CHECK_STATUS(status, NT_STATUS_OK);
533         fnum2 = io.ntcreatex.out.file.fnum;
534         CHECK_VAL(break_info.count, 0);
535         CHECK_VAL(break_info.failures, 0);
536         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
537
538         printf("write should trigger a break to none\n");
539         {
540                 union smb_write wr;
541                 wr.write.level = RAW_WRITE_WRITE;
542                 wr.write.in.file.fnum = fnum;
543                 wr.write.in.count = 1;
544                 wr.write.in.offset = 0;
545                 wr.write.in.remaining = 0;
546                 wr.write.in.data = (const uint8_t *)"x";
547                 status = smb_raw_write(cli1->tree, &wr);
548                 CHECK_STATUS(status, NT_STATUS_OK);
549         }
550
551         /* Now the oplock break request comes in. But right now we can't
552          * answer it. Do another write */
553
554         msleep(100);
555         
556         {
557                 union smb_write wr;
558                 wr.write.level = RAW_WRITE_WRITE;
559                 wr.write.in.file.fnum = fnum;
560                 wr.write.in.count = 1;
561                 wr.write.in.offset = 0;
562                 wr.write.in.remaining = 0;
563                 wr.write.in.data = (const uint8_t *)"x";
564                 status = smb_raw_write(cli1->tree, &wr);
565                 CHECK_STATUS(status, NT_STATUS_OK);
566         }
567
568         CHECK_VAL(break_info.count, 1);
569         CHECK_VAL(break_info.fnum, fnum2);
570         CHECK_VAL(break_info.level, 0);
571         CHECK_VAL(break_info.failures, 0);
572
573         smbcli_close(cli1->tree, fnum);
574         smbcli_close(cli2->tree, fnum2);
575         smbcli_unlink(cli1->tree, fname);
576
577         /* Test if a set-eof on pathname breaks an exclusive oplock. */
578         printf("Test if setpathinfo set EOF breaks oplocks.\n");
579
580         ZERO_STRUCT(break_info);
581         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
582
583         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
584                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
585                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
586         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
587         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
588                 NTCREATEX_SHARE_ACCESS_WRITE|
589                 NTCREATEX_SHARE_ACCESS_DELETE;
590         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
591         status = smb_raw_open(cli1->tree, mem_ctx, &io);
592         CHECK_STATUS(status, NT_STATUS_OK);
593         fnum = io.ntcreatex.out.file.fnum;
594         CHECK_VAL(break_info.count, 0);
595         CHECK_VAL(break_info.failures, 0);
596         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
597         
598         ZERO_STRUCT(sfi);
599         sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
600         sfi.generic.in.file.path = fname;
601         sfi.end_of_file_info.in.size = 100;
602
603         status = smb_raw_setpathinfo(cli2->tree, &sfi);
604
605         CHECK_STATUS(status, NT_STATUS_OK);
606         CHECK_VAL(break_info.count, 1);
607         CHECK_VAL(break_info.failures, 0);
608         CHECK_VAL(break_info.level, 0);
609
610         smbcli_close(cli1->tree, fnum);
611         smbcli_unlink(cli1->tree, fname);
612
613         /* Test if a set-allocation size on pathname breaks an exclusive oplock. */
614         printf("Test if setpathinfo allocation size breaks oplocks.\n");
615
616         ZERO_STRUCT(break_info);
617         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
618
619         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
620                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
621                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
622         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
623         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
624                 NTCREATEX_SHARE_ACCESS_WRITE|
625                 NTCREATEX_SHARE_ACCESS_DELETE;
626         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
627         status = smb_raw_open(cli1->tree, mem_ctx, &io);
628         CHECK_STATUS(status, NT_STATUS_OK);
629         fnum = io.ntcreatex.out.file.fnum;
630         CHECK_VAL(break_info.count, 0);
631         CHECK_VAL(break_info.failures, 0);
632         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
633         
634         ZERO_STRUCT(sfi);
635         sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
636         sfi.generic.in.file.path = fname;
637         sfi.allocation_info.in.alloc_size = 65536 * 8;
638
639         status = smb_raw_setpathinfo(cli2->tree, &sfi);
640
641         CHECK_STATUS(status, NT_STATUS_OK);
642         CHECK_VAL(break_info.count, 1);
643         CHECK_VAL(break_info.failures, 0);
644         CHECK_VAL(break_info.level, 0);
645
646         smbcli_close(cli1->tree, fnum);
647         smbcli_close(cli2->tree, fnum2);
648         smbcli_unlink(cli1->tree, fname);
649
650         printf("open with batch oplock\n");
651         ZERO_STRUCT(break_info);
652         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
653
654         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
655                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
656                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
657         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
658         status = smb_raw_open(cli1->tree, mem_ctx, &io);
659         CHECK_STATUS(status, NT_STATUS_OK);
660         fnum = io.ntcreatex.out.file.fnum;
661         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
662
663         ZERO_STRUCT(break_info);
664
665         printf("second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
666
667         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
668                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
669                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
670         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
671         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
672         status = smb_raw_open(cli2->tree, mem_ctx, &io);
673         CHECK_STATUS(status, NT_STATUS_OK);
674         fnum2 = io.ntcreatex.out.file.fnum;
675         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
676         CHECK_VAL(break_info.count, 1);
677         CHECK_VAL(break_info.failures, 0);
678
679         smbcli_close(cli1->tree, fnum);
680         smbcli_close(cli2->tree, fnum2);
681         smbcli_unlink(cli1->tree, fname);
682
683         printf("open with batch oplock\n");
684         ZERO_STRUCT(break_info);
685         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
686
687         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
688                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
689                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
690         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
691         status = smb_raw_open(cli1->tree, mem_ctx, &io);
692         CHECK_STATUS(status, NT_STATUS_OK);
693         fnum = io.ntcreatex.out.file.fnum;
694         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
695
696         ZERO_STRUCT(break_info);
697
698         printf("second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
699
700         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
701                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
702                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
703         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
704         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
705         status = smb_raw_open(cli2->tree, mem_ctx, &io);
706         CHECK_STATUS(status, NT_STATUS_OK);
707         fnum2 = io.ntcreatex.out.file.fnum;
708         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
709         CHECK_VAL(break_info.count, 1);
710         CHECK_VAL(break_info.failures, 0);
711
712         smbcli_close(cli1->tree, fnum);
713         smbcli_close(cli2->tree, fnum2);
714         smbcli_unlink(cli1->tree, fname);
715
716
717 done:
718         smbcli_close(cli1->tree, fnum);
719         smbcli_close(cli2->tree, fnum2);
720         smbcli_unlink(cli1->tree, fname);
721         return ret;
722 }
723
724
725 /* 
726    basic testing of oplocks
727 */
728 BOOL torture_raw_oplock(struct torture_context *torture)
729 {
730         struct smbcli_state *cli1, *cli2;
731         BOOL ret = True;
732         TALLOC_CTX *mem_ctx;
733
734         if (!torture_open_connection(&cli1, 0)) {
735                 return False;
736         }
737
738         if (!torture_open_connection_ev(
739                     &cli2, 1, cli1->transport->socket->event.ctx)) {
740                 return False;
741         }
742
743         if (!torture_setup_dir(cli1, BASEDIR)) {
744                 return False;
745         }
746
747         mem_ctx = talloc_init("torture_raw_oplock");
748
749         if (!test_oplock(cli1, cli2, mem_ctx)) {
750                 ret = False;
751         }
752
753         smb_raw_exit(cli1->session);
754         smbcli_deltree(cli1->tree, BASEDIR);
755         torture_close_connection(cli1);
756         torture_close_connection(cli2);
757         talloc_free(mem_ctx);
758         return ret;
759 }
760
761
762 /* 
763    stress testing of oplocks
764 */
765 BOOL torture_bench_oplock(struct torture_context *torture)
766 {
767         struct smbcli_state **cli;
768         BOOL ret = True;
769         TALLOC_CTX *mem_ctx = talloc_new(torture);
770         extern int torture_nprocs;
771         int i, count=0;
772         int timelimit = torture_setting_int(torture, "timelimit", 10);
773         union smb_open io;
774         struct timeval tv;
775         struct event_context *ev = event_context_find(mem_ctx);
776
777         cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
778
779         printf("Opening %d connections\n", torture_nprocs);
780         for (i=0;i<torture_nprocs;i++) {
781                 if (!torture_open_connection_ev(&cli[i], i, ev)) {
782                         return False;
783                 }
784                 talloc_steal(mem_ctx, cli[i]);
785                 smbcli_oplock_handler(cli[i]->transport, oplock_handler_close, 
786                                       cli[i]->tree);
787         }
788
789         if (!torture_setup_dir(cli[0], BASEDIR)) {
790                 ret = False;
791                 goto done;
792         }
793
794         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
795         io.ntcreatex.in.root_fid = 0;
796         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
797         io.ntcreatex.in.alloc_size = 0;
798         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
799         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
800         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
801         io.ntcreatex.in.create_options = 0;
802         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
803         io.ntcreatex.in.security_flags = 0;
804         io.ntcreatex.in.fname = BASEDIR "\\test.dat";
805         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
806                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
807                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
808
809         tv = timeval_current(); 
810
811         /*
812           we open the same file with SHARE_ACCESS_NONE from all the
813           connections in a round robin fashion. Each open causes an
814           oplock break on the previous connection, which is answered
815           by the oplock_handler_close() to close the file.
816
817           This measures how fast we can pass on oplocks, and stresses
818           the oplock handling code
819         */
820         printf("Running for %d seconds\n", timelimit);
821         while (timeval_elapsed(&tv) < timelimit) {
822                 for (i=0;i<torture_nprocs;i++) {
823                         NTSTATUS status;
824
825                         status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
826                         CHECK_STATUS(status, NT_STATUS_OK);
827                         count++;
828                 }
829                 printf("%.2f ops/second\r", count/timeval_elapsed(&tv));
830         }
831
832         printf("%.2f ops/second\n", count/timeval_elapsed(&tv));
833
834         smb_raw_exit(cli[torture_nprocs-1]->session);
835         
836 done:
837         smb_raw_exit(cli[0]->session);
838         smbcli_deltree(cli[0]->tree, BASEDIR);
839         talloc_free(mem_ctx);
840         return ret;
841 }