2 Unix SMB/CIFS implementation.
3 basic raw test suite for oplocks
4 Copyright (C) Andrew Tridgell 2003
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.
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.
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.
23 #define CHECK_VAL(v, correct) do { \
24 if ((v) != (correct)) { \
25 printf("(%d) wrong value for %s 0x%x - 0x%x\n", \
26 __LINE__, #v, (int)v, (int)correct); \
30 #define CHECK_STATUS(status, correct) do { \
31 if (!NT_STATUS_EQUAL(status, correct)) { \
32 printf("(%d) Incorrect status %s - should be %s\n", \
33 __LINE__, nt_errstr(status), nt_errstr(correct)); \
46 a handler function for oplock break requests
48 static BOOL oplock_handler_ack(struct cli_transport *transport, uint16 tid, uint16 fnum, uint8 level, void *private)
50 struct cli_tree *tree = private;
51 break_info.fnum = fnum;
52 break_info.level = level;
55 printf("Acking in oplock handler\n");
57 return cli_oplock_ack(tree, fnum, level);
61 a handler function for oplock break requests - close the file
63 static BOOL oplock_handler_close(struct cli_transport *transport, uint16 tid, uint16 fnum, uint8 level, void *private)
67 struct cli_tree *tree = private;
69 break_info.fnum = fnum;
70 break_info.level = level;
73 io.close.level = RAW_CLOSE_CLOSE;
74 io.close.in.fnum = fnum;
75 io.close.in.write_time = 0;
76 status = smb_raw_close(tree, &io);
78 printf("Closing in oplock handler\n");
80 if (!NT_STATUS_IS_OK(status)) {
81 printf("close failed in oplock_handler_close\n");
90 static BOOL test_oplock(struct cli_state *cli, TALLOC_CTX *mem_ctx)
92 const char *fname = "\\test_oplock.dat";
96 struct smb_unlink unl;
101 cli_unlink(cli->tree, fname);
103 cli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
108 io.generic.level = RAW_OPEN_NTCREATEX;
109 io.ntcreatex.in.root_fid = 0;
110 io.ntcreatex.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
111 io.ntcreatex.in.alloc_size = 0;
112 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
113 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
114 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
115 io.ntcreatex.in.create_options = 0;
116 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
117 io.ntcreatex.in.security_flags = 0;
118 io.ntcreatex.in.fname = fname;
120 printf("open a file with a normal oplock\n");
121 ZERO_STRUCT(break_info);
122 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
124 status = smb_raw_open(cli->tree, mem_ctx, &io);
125 CHECK_STATUS(status, NT_STATUS_OK);
126 fnum = io.ntcreatex.out.fnum;
127 CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
129 printf("unlink it - should be no break\n");
130 unl.in.pattern = fname;
132 status = smb_raw_unlink(cli->tree, &unl);
133 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
134 CHECK_VAL(break_info.count, 0);
136 cli_close(cli->tree, fnum);
139 with a batch oplock we get a break
141 printf("open with batch oplock\n");
142 ZERO_STRUCT(break_info);
143 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
144 NTCREATEX_FLAGS_REQUEST_OPLOCK |
145 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
146 status = smb_raw_open(cli->tree, mem_ctx, &io);
147 CHECK_STATUS(status, NT_STATUS_OK);
148 fnum = io.ntcreatex.out.fnum;
149 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
151 printf("unlink should generate a break\n");
152 unl.in.pattern = fname;
154 status = smb_raw_unlink(cli->tree, &unl);
155 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
157 CHECK_VAL(break_info.fnum, fnum);
158 CHECK_VAL(break_info.level, 2);
159 CHECK_VAL(break_info.count, 1);
162 cli_close(cli->tree, fnum);
164 printf("if we close on break then the unlink can succeed\n");
165 ZERO_STRUCT(break_info);
166 cli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
167 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
168 NTCREATEX_FLAGS_REQUEST_OPLOCK |
169 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
170 status = smb_raw_open(cli->tree, mem_ctx, &io);
171 CHECK_STATUS(status, NT_STATUS_OK);
172 fnum = io.ntcreatex.out.fnum;
173 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
175 unl.in.pattern = fname;
177 ZERO_STRUCT(break_info);
178 status = smb_raw_unlink(cli->tree, &unl);
179 CHECK_STATUS(status, NT_STATUS_OK);
181 CHECK_VAL(break_info.fnum, fnum);
182 CHECK_VAL(break_info.level, 2);
183 CHECK_VAL(break_info.count, 1);
185 printf("a self read should not cause a break\n");
186 ZERO_STRUCT(break_info);
187 cli_close(cli->tree, fnum);
188 cli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
190 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
191 NTCREATEX_FLAGS_REQUEST_OPLOCK |
192 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
193 status = smb_raw_open(cli->tree, mem_ctx, &io);
194 CHECK_STATUS(status, NT_STATUS_OK);
195 fnum = io.ntcreatex.out.fnum;
196 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
198 rd.read.level = RAW_READ_READ;
199 rd.read.in.fnum = fnum;
200 rd.read.in.count = 1;
201 rd.read.in.offset = 0;
202 rd.read.in.remaining = 0;
203 status = smb_raw_read(cli->tree, &rd);
204 CHECK_STATUS(status, NT_STATUS_OK);
205 CHECK_VAL(break_info.count, 0);
208 printf("a 2nd open should give a break\n");
209 ZERO_STRUCT(break_info);
210 cli_close(cli->tree, fnum);
211 cli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
213 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
214 NTCREATEX_FLAGS_REQUEST_OPLOCK |
215 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
216 status = smb_raw_open(cli->tree, mem_ctx, &io);
217 CHECK_STATUS(status, NT_STATUS_OK);
218 fnum = io.ntcreatex.out.fnum;
219 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
221 ZERO_STRUCT(break_info);
223 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
224 status = smb_raw_open(cli->tree, mem_ctx, &io);
225 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
227 CHECK_VAL(break_info.count, 1);
228 CHECK_VAL(break_info.fnum, fnum);
229 CHECK_VAL(break_info.level, 2);
231 printf("a 2nd open should get an oplock when we close instead of ack\n");
232 ZERO_STRUCT(break_info);
233 cli_close(cli->tree, fnum);
234 cli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
236 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
237 NTCREATEX_FLAGS_REQUEST_OPLOCK |
238 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
239 status = smb_raw_open(cli->tree, mem_ctx, &io);
240 CHECK_STATUS(status, NT_STATUS_OK);
241 fnum2 = io.ntcreatex.out.fnum;
242 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
244 ZERO_STRUCT(break_info);
246 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
247 NTCREATEX_FLAGS_REQUEST_OPLOCK |
248 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
249 status = smb_raw_open(cli->tree, mem_ctx, &io);
250 CHECK_STATUS(status, NT_STATUS_OK);
251 fnum = io.ntcreatex.out.fnum;
252 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
254 CHECK_VAL(break_info.count, 1);
255 CHECK_VAL(break_info.fnum, fnum2);
256 CHECK_VAL(break_info.level, 2);
260 cli_close(cli->tree, fnum);
261 cli_unlink(cli->tree, fname);
267 basic testing of oplocks
269 BOOL torture_raw_oplock(int dummy)
271 struct cli_state *cli1;
275 if (!torture_open_connection(&cli1)) {
279 mem_ctx = talloc_init("torture_raw_oplock");
281 if (!test_oplock(cli1, mem_ctx)) {
285 torture_close_connection(cli1);
286 talloc_destroy(mem_ctx);