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_t tid, uint16_t 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_t tid, uint16_t 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);
258 cli_close(cli->tree, fnum);
260 printf("open with batch oplock\n");
261 ZERO_STRUCT(break_info);
262 cli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
264 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
265 NTCREATEX_FLAGS_REQUEST_OPLOCK |
266 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
267 status = smb_raw_open(cli->tree, mem_ctx, &io);
268 CHECK_STATUS(status, NT_STATUS_OK);
269 fnum = io.ntcreatex.out.fnum;
270 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
272 ZERO_STRUCT(break_info);
273 printf("second open with attributes only shouldn't cause oplock break\n");
275 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
276 NTCREATEX_FLAGS_REQUEST_OPLOCK |
277 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
278 io.ntcreatex.in.access_mask = SA_RIGHT_FILE_READ_ATTRIBUTES|SA_RIGHT_FILE_WRITE_ATTRIBUTES|STD_RIGHT_SYNCHRONIZE_ACCESS;
279 status = smb_raw_open(cli->tree, mem_ctx, &io);
280 CHECK_STATUS(status, NT_STATUS_OK);
281 fnum2 = io.ntcreatex.out.fnum;
282 CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
283 CHECK_VAL(break_info.count, 0);
284 CHECK_VAL(break_info.fnum, 0);
285 CHECK_VAL(break_info.level, 0);
288 cli_close(cli->tree, fnum);
289 cli_close(cli->tree, fnum2);
290 cli_unlink(cli->tree, fname);
296 basic testing of oplocks
298 BOOL torture_raw_oplock(int dummy)
300 struct cli_state *cli1;
304 if (!torture_open_connection(&cli1)) {
308 mem_ctx = talloc_init("torture_raw_oplock");
310 if (!test_oplock(cli1, mem_ctx)) {
314 torture_close_connection(cli1);
315 talloc_destroy(mem_ctx);