1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 | unlink test suite
|
---|
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 3 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, see <http://www.gnu.org/licenses/>.
|
---|
18 | */
|
---|
19 |
|
---|
20 | #include "includes.h"
|
---|
21 | #include "torture/torture.h"
|
---|
22 | #include "system/filesys.h"
|
---|
23 | #include "libcli/raw/libcliraw.h"
|
---|
24 | #include "libcli/raw/raw_proto.h"
|
---|
25 | #include "libcli/libcli.h"
|
---|
26 | #include "torture/util.h"
|
---|
27 |
|
---|
28 | #define CHECK_STATUS(status, correct) do { \
|
---|
29 | if (!NT_STATUS_EQUAL(status, correct)) { \
|
---|
30 | printf("(%s) Incorrect status %s - should be %s\n", \
|
---|
31 | __location__, nt_errstr(status), nt_errstr(correct)); \
|
---|
32 | ret = false; \
|
---|
33 | goto done; \
|
---|
34 | }} while (0)
|
---|
35 |
|
---|
36 | #define BASEDIR "\\testunlink"
|
---|
37 |
|
---|
38 | /*
|
---|
39 | test unlink ops
|
---|
40 | */
|
---|
41 | static bool test_unlink(struct torture_context *tctx, struct smbcli_state *cli)
|
---|
42 | {
|
---|
43 | union smb_unlink io;
|
---|
44 | NTSTATUS status;
|
---|
45 | bool ret = true;
|
---|
46 | const char *fname = BASEDIR "\\test.txt";
|
---|
47 |
|
---|
48 | if (!torture_setup_dir(cli, BASEDIR)) {
|
---|
49 | return false;
|
---|
50 | }
|
---|
51 |
|
---|
52 | printf("Trying non-existant file\n");
|
---|
53 | io.unlink.in.pattern = fname;
|
---|
54 | io.unlink.in.attrib = 0;
|
---|
55 | status = smb_raw_unlink(cli->tree, &io);
|
---|
56 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
57 |
|
---|
58 | smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
---|
59 |
|
---|
60 | io.unlink.in.pattern = fname;
|
---|
61 | io.unlink.in.attrib = 0;
|
---|
62 | status = smb_raw_unlink(cli->tree, &io);
|
---|
63 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
64 |
|
---|
65 | printf("Trying a hidden file\n");
|
---|
66 | smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
---|
67 | torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
|
---|
68 |
|
---|
69 | io.unlink.in.pattern = fname;
|
---|
70 | io.unlink.in.attrib = 0;
|
---|
71 | status = smb_raw_unlink(cli->tree, &io);
|
---|
72 | CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
---|
73 |
|
---|
74 | io.unlink.in.pattern = fname;
|
---|
75 | io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
|
---|
76 | status = smb_raw_unlink(cli->tree, &io);
|
---|
77 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
78 |
|
---|
79 | io.unlink.in.pattern = fname;
|
---|
80 | io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
|
---|
81 | status = smb_raw_unlink(cli->tree, &io);
|
---|
82 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
83 |
|
---|
84 | printf("Trying a directory\n");
|
---|
85 | io.unlink.in.pattern = BASEDIR;
|
---|
86 | io.unlink.in.attrib = 0;
|
---|
87 | status = smb_raw_unlink(cli->tree, &io);
|
---|
88 | CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
|
---|
89 |
|
---|
90 | io.unlink.in.pattern = BASEDIR;
|
---|
91 | io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
---|
92 | status = smb_raw_unlink(cli->tree, &io);
|
---|
93 | CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
|
---|
94 |
|
---|
95 | printf("Trying a bad path\n");
|
---|
96 | io.unlink.in.pattern = "..";
|
---|
97 | io.unlink.in.attrib = 0;
|
---|
98 | status = smb_raw_unlink(cli->tree, &io);
|
---|
99 | CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
---|
100 |
|
---|
101 | io.unlink.in.pattern = "\\..";
|
---|
102 | io.unlink.in.attrib = 0;
|
---|
103 | status = smb_raw_unlink(cli->tree, &io);
|
---|
104 | CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
---|
105 |
|
---|
106 | io.unlink.in.pattern = BASEDIR "\\..\\..";
|
---|
107 | io.unlink.in.attrib = 0;
|
---|
108 | status = smb_raw_unlink(cli->tree, &io);
|
---|
109 | CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
---|
110 |
|
---|
111 | io.unlink.in.pattern = BASEDIR "\\..";
|
---|
112 | io.unlink.in.attrib = 0;
|
---|
113 | status = smb_raw_unlink(cli->tree, &io);
|
---|
114 | CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
|
---|
115 |
|
---|
116 | printf("Trying wildcards\n");
|
---|
117 | smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
---|
118 | io.unlink.in.pattern = BASEDIR "\\t*.t";
|
---|
119 | io.unlink.in.attrib = 0;
|
---|
120 | status = smb_raw_unlink(cli->tree, &io);
|
---|
121 | CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
---|
122 |
|
---|
123 | io.unlink.in.pattern = BASEDIR "\\z*";
|
---|
124 | io.unlink.in.attrib = 0;
|
---|
125 | status = smb_raw_unlink(cli->tree, &io);
|
---|
126 | CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
---|
127 |
|
---|
128 | io.unlink.in.pattern = BASEDIR "\\z*";
|
---|
129 | io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
---|
130 | status = smb_raw_unlink(cli->tree, &io);
|
---|
131 |
|
---|
132 | if (torture_setting_bool(tctx, "samba3", false)) {
|
---|
133 | /*
|
---|
134 | * In Samba3 we gave up upon getting the error codes in
|
---|
135 | * wildcard unlink correct. Trying gentest showed that this is
|
---|
136 | * irregular beyond our capabilities. So for
|
---|
137 | * FILE_ATTRIBUTE_DIRECTORY we always return NAME_INVALID.
|
---|
138 | * Tried by jra and vl. If others feel like solving this
|
---|
139 | * puzzle, please tell us :-)
|
---|
140 | */
|
---|
141 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
142 | }
|
---|
143 | else {
|
---|
144 | CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
---|
145 | }
|
---|
146 |
|
---|
147 | io.unlink.in.pattern = BASEDIR "\\*";
|
---|
148 | io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
---|
149 | status = smb_raw_unlink(cli->tree, &io);
|
---|
150 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
151 |
|
---|
152 | io.unlink.in.pattern = BASEDIR "\\?";
|
---|
153 | io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
---|
154 | status = smb_raw_unlink(cli->tree, &io);
|
---|
155 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
156 |
|
---|
157 | io.unlink.in.pattern = BASEDIR "\\t*";
|
---|
158 | io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
---|
159 | status = smb_raw_unlink(cli->tree, &io);
|
---|
160 | if (torture_setting_bool(tctx, "samba3", false)) {
|
---|
161 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
162 | }
|
---|
163 | else {
|
---|
164 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
165 | }
|
---|
166 |
|
---|
167 | smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
---|
168 |
|
---|
169 | io.unlink.in.pattern = BASEDIR "\\*.dat";
|
---|
170 | io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
---|
171 | status = smb_raw_unlink(cli->tree, &io);
|
---|
172 | if (torture_setting_bool(tctx, "samba3", false)) {
|
---|
173 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
---|
174 | }
|
---|
175 | else {
|
---|
176 | CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
---|
177 | }
|
---|
178 |
|
---|
179 | io.unlink.in.pattern = BASEDIR "\\*.tx?";
|
---|
180 | io.unlink.in.attrib = 0;
|
---|
181 | status = smb_raw_unlink(cli->tree, &io);
|
---|
182 | if (torture_setting_bool(tctx, "samba3", false)) {
|
---|
183 | CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
---|
184 | }
|
---|
185 | else {
|
---|
186 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
187 | }
|
---|
188 |
|
---|
189 | status = smb_raw_unlink(cli->tree, &io);
|
---|
190 | CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
---|
191 |
|
---|
192 |
|
---|
193 | done:
|
---|
194 | smb_raw_exit(cli->session);
|
---|
195 | smbcli_deltree(cli->tree, BASEDIR);
|
---|
196 | return ret;
|
---|
197 | }
|
---|
198 |
|
---|
199 |
|
---|
200 | /*
|
---|
201 | test delete on close
|
---|
202 | */
|
---|
203 | static bool test_delete_on_close(struct torture_context *tctx,
|
---|
204 | struct smbcli_state *cli)
|
---|
205 | {
|
---|
206 | union smb_open op;
|
---|
207 | union smb_unlink io;
|
---|
208 | struct smb_rmdir dio;
|
---|
209 | NTSTATUS status;
|
---|
210 | bool ret = true;
|
---|
211 | int fnum, fnum2;
|
---|
212 | const char *fname = BASEDIR "\\test.txt";
|
---|
213 | const char *dname = BASEDIR "\\test.dir";
|
---|
214 | const char *inside = BASEDIR "\\test.dir\\test.txt";
|
---|
215 | union smb_setfileinfo sfinfo;
|
---|
216 |
|
---|
217 | if (!torture_setup_dir(cli, BASEDIR)) {
|
---|
218 | return false;
|
---|
219 | }
|
---|
220 |
|
---|
221 | dio.in.path = dname;
|
---|
222 |
|
---|
223 | io.unlink.in.pattern = fname;
|
---|
224 | io.unlink.in.attrib = 0;
|
---|
225 | status = smb_raw_unlink(cli->tree, &io);
|
---|
226 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
227 |
|
---|
228 | printf("Testing with delete_on_close 0\n");
|
---|
229 | fnum = create_complex_file(cli, tctx, fname);
|
---|
230 |
|
---|
231 | sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
|
---|
232 | sfinfo.disposition_info.in.file.fnum = fnum;
|
---|
233 | sfinfo.disposition_info.in.delete_on_close = 0;
|
---|
234 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
235 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
236 |
|
---|
237 | smbcli_close(cli->tree, fnum);
|
---|
238 |
|
---|
239 | status = smb_raw_unlink(cli->tree, &io);
|
---|
240 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
241 |
|
---|
242 | printf("Testing with delete_on_close 1\n");
|
---|
243 | fnum = create_complex_file(cli, tctx, fname);
|
---|
244 | sfinfo.disposition_info.in.file.fnum = fnum;
|
---|
245 | sfinfo.disposition_info.in.delete_on_close = 1;
|
---|
246 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
247 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
248 |
|
---|
249 | smbcli_close(cli->tree, fnum);
|
---|
250 |
|
---|
251 | status = smb_raw_unlink(cli->tree, &io);
|
---|
252 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
253 |
|
---|
254 |
|
---|
255 | printf("Testing with directory and delete_on_close 0\n");
|
---|
256 | status = create_directory_handle(cli->tree, dname, &fnum);
|
---|
257 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
258 |
|
---|
259 | sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
|
---|
260 | sfinfo.disposition_info.in.file.fnum = fnum;
|
---|
261 | sfinfo.disposition_info.in.delete_on_close = 0;
|
---|
262 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
263 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
264 |
|
---|
265 | smbcli_close(cli->tree, fnum);
|
---|
266 |
|
---|
267 | status = smb_raw_rmdir(cli->tree, &dio);
|
---|
268 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
269 |
|
---|
270 | printf("Testing with directory delete_on_close 1\n");
|
---|
271 | status = create_directory_handle(cli->tree, dname, &fnum);
|
---|
272 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
273 |
|
---|
274 | sfinfo.disposition_info.in.file.fnum = fnum;
|
---|
275 | sfinfo.disposition_info.in.delete_on_close = 1;
|
---|
276 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
277 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
278 |
|
---|
279 | smbcli_close(cli->tree, fnum);
|
---|
280 |
|
---|
281 | status = smb_raw_rmdir(cli->tree, &dio);
|
---|
282 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
283 |
|
---|
284 |
|
---|
285 | if (!torture_setting_bool(tctx, "samba3", false)) {
|
---|
286 |
|
---|
287 | /*
|
---|
288 | * Known deficiency, also skipped in base-delete.
|
---|
289 | */
|
---|
290 |
|
---|
291 | printf("Testing with non-empty directory delete_on_close\n");
|
---|
292 | status = create_directory_handle(cli->tree, dname, &fnum);
|
---|
293 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
294 |
|
---|
295 | fnum2 = create_complex_file(cli, tctx, inside);
|
---|
296 |
|
---|
297 | sfinfo.disposition_info.in.file.fnum = fnum;
|
---|
298 | sfinfo.disposition_info.in.delete_on_close = 1;
|
---|
299 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
300 | CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
---|
301 |
|
---|
302 | sfinfo.disposition_info.in.file.fnum = fnum2;
|
---|
303 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
304 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
305 |
|
---|
306 | sfinfo.disposition_info.in.file.fnum = fnum;
|
---|
307 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
308 | CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
---|
309 |
|
---|
310 | smbcli_close(cli->tree, fnum2);
|
---|
311 |
|
---|
312 | status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
---|
313 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
314 |
|
---|
315 | smbcli_close(cli->tree, fnum);
|
---|
316 |
|
---|
317 | status = smb_raw_rmdir(cli->tree, &dio);
|
---|
318 | CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
---|
319 | }
|
---|
320 |
|
---|
321 | printf("Testing open dir with delete_on_close\n");
|
---|
322 | status = create_directory_handle(cli->tree, dname, &fnum);
|
---|
323 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
324 |
|
---|
325 | smbcli_close(cli->tree, fnum);
|
---|
326 | fnum2 = create_complex_file(cli, tctx, inside);
|
---|
327 | smbcli_close(cli->tree, fnum2);
|
---|
328 |
|
---|
329 | op.generic.level = RAW_OPEN_NTCREATEX;
|
---|
330 | op.ntcreatex.in.root_fid.fnum = 0;
|
---|
331 | op.ntcreatex.in.flags = 0;
|
---|
332 | op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
---|
333 | op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
---|
334 | op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
---|
335 | op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
---|
336 | op.ntcreatex.in.alloc_size = 0;
|
---|
337 | op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
---|
338 | op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
---|
339 | op.ntcreatex.in.security_flags = 0;
|
---|
340 | op.ntcreatex.in.fname = dname;
|
---|
341 |
|
---|
342 | status = smb_raw_open(cli->tree, tctx, &op);
|
---|
343 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
344 | fnum = op.ntcreatex.out.file.fnum;
|
---|
345 |
|
---|
346 | smbcli_close(cli->tree, fnum);
|
---|
347 |
|
---|
348 | status = smb_raw_rmdir(cli->tree, &dio);
|
---|
349 | CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
---|
350 |
|
---|
351 | smbcli_deltree(cli->tree, dname);
|
---|
352 |
|
---|
353 | printf("Testing double open dir with second delete_on_close\n");
|
---|
354 | status = create_directory_handle(cli->tree, dname, &fnum);
|
---|
355 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
356 | smbcli_close(cli->tree, fnum);
|
---|
357 |
|
---|
358 | fnum2 = create_complex_file(cli, tctx, inside);
|
---|
359 | smbcli_close(cli->tree, fnum2);
|
---|
360 |
|
---|
361 | op.generic.level = RAW_OPEN_NTCREATEX;
|
---|
362 | op.ntcreatex.in.root_fid.fnum = 0;
|
---|
363 | op.ntcreatex.in.flags = 0;
|
---|
364 | op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
---|
365 | op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
---|
366 | op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
---|
367 | op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
---|
368 | op.ntcreatex.in.alloc_size = 0;
|
---|
369 | op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
---|
370 | op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
---|
371 | op.ntcreatex.in.security_flags = 0;
|
---|
372 | op.ntcreatex.in.fname = dname;
|
---|
373 |
|
---|
374 | status = smb_raw_open(cli->tree, tctx, &op);
|
---|
375 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
376 | fnum2 = op.ntcreatex.out.file.fnum;
|
---|
377 |
|
---|
378 | smbcli_close(cli->tree, fnum2);
|
---|
379 |
|
---|
380 | status = smb_raw_rmdir(cli->tree, &dio);
|
---|
381 | CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
---|
382 |
|
---|
383 | smbcli_deltree(cli->tree, dname);
|
---|
384 |
|
---|
385 | printf("Testing pre-existing open dir with second delete_on_close\n");
|
---|
386 | status = create_directory_handle(cli->tree, dname, &fnum);
|
---|
387 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
388 |
|
---|
389 | smbcli_close(cli->tree, fnum);
|
---|
390 |
|
---|
391 | fnum = create_complex_file(cli, tctx, inside);
|
---|
392 | smbcli_close(cli->tree, fnum);
|
---|
393 |
|
---|
394 | /* we have a dir with a file in it, no handles open */
|
---|
395 |
|
---|
396 | op.generic.level = RAW_OPEN_NTCREATEX;
|
---|
397 | op.ntcreatex.in.root_fid.fnum = 0;
|
---|
398 | op.ntcreatex.in.flags = 0;
|
---|
399 | op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
---|
400 | op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
---|
401 | op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
---|
402 | op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
|
---|
403 | op.ntcreatex.in.alloc_size = 0;
|
---|
404 | op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
---|
405 | op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
---|
406 | op.ntcreatex.in.security_flags = 0;
|
---|
407 | op.ntcreatex.in.fname = dname;
|
---|
408 |
|
---|
409 | status = smb_raw_open(cli->tree, tctx, &op);
|
---|
410 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
411 | fnum = op.ntcreatex.out.file.fnum;
|
---|
412 |
|
---|
413 | /* open without delete on close */
|
---|
414 | op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
|
---|
415 | status = smb_raw_open(cli->tree, tctx, &op);
|
---|
416 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
417 | fnum2 = op.ntcreatex.out.file.fnum;
|
---|
418 |
|
---|
419 | /* close 2nd file handle */
|
---|
420 | smbcli_close(cli->tree, fnum2);
|
---|
421 |
|
---|
422 | status = smb_raw_rmdir(cli->tree, &dio);
|
---|
423 | CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
---|
424 |
|
---|
425 |
|
---|
426 | smbcli_close(cli->tree, fnum);
|
---|
427 |
|
---|
428 | status = smb_raw_rmdir(cli->tree, &dio);
|
---|
429 | CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
---|
430 |
|
---|
431 | done:
|
---|
432 | smb_raw_exit(cli->session);
|
---|
433 | smbcli_deltree(cli->tree, BASEDIR);
|
---|
434 | return ret;
|
---|
435 | }
|
---|
436 |
|
---|
437 |
|
---|
438 | struct unlink_defer_cli_state {
|
---|
439 | struct torture_context *tctx;
|
---|
440 | struct smbcli_state *cli1;
|
---|
441 | };
|
---|
442 |
|
---|
443 | /*
|
---|
444 | * A handler function for oplock break requests. Ack it as a break to none
|
---|
445 | */
|
---|
446 | static bool oplock_handler_ack_to_none(struct smbcli_transport *transport,
|
---|
447 | uint16_t tid, uint16_t fnum,
|
---|
448 | uint8_t level, void *private_data)
|
---|
449 | {
|
---|
450 | struct unlink_defer_cli_state *ud_cli_state =
|
---|
451 | (struct unlink_defer_cli_state *)private_data;
|
---|
452 | union smb_setfileinfo sfinfo;
|
---|
453 | bool ret;
|
---|
454 | struct smbcli_request *req = NULL;
|
---|
455 |
|
---|
456 | torture_comment(ud_cli_state->tctx, "delete the file before sending "
|
---|
457 | "the ack.");
|
---|
458 |
|
---|
459 | /* cli1: set delete on close */
|
---|
460 | sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
|
---|
461 | sfinfo.disposition_info.in.file.fnum = fnum;
|
---|
462 | sfinfo.disposition_info.in.delete_on_close = 1;
|
---|
463 | req = smb_raw_setfileinfo_send(ud_cli_state->cli1->tree, &sfinfo);
|
---|
464 |
|
---|
465 | smbcli_close(ud_cli_state->cli1->tree, fnum);
|
---|
466 |
|
---|
467 | torture_comment(ud_cli_state->tctx, "Acking the oplock to NONE\n");
|
---|
468 |
|
---|
469 | ret = smbcli_oplock_ack(ud_cli_state->cli1->tree, fnum,
|
---|
470 | OPLOCK_BREAK_TO_NONE);
|
---|
471 |
|
---|
472 | return ret;
|
---|
473 | }
|
---|
474 |
|
---|
475 | static bool test_unlink_defer(struct torture_context *tctx,
|
---|
476 | struct smbcli_state *cli1,
|
---|
477 | struct smbcli_state *cli2)
|
---|
478 | {
|
---|
479 | const char *fname = BASEDIR "\\test_unlink_defer.dat";
|
---|
480 | NTSTATUS status;
|
---|
481 | bool ret = true;
|
---|
482 | union smb_open io;
|
---|
483 | union smb_unlink unl;
|
---|
484 | uint16_t fnum=0;
|
---|
485 | struct unlink_defer_cli_state ud_cli_state = {};
|
---|
486 |
|
---|
487 | if (!torture_setup_dir(cli1, BASEDIR)) {
|
---|
488 | return false;
|
---|
489 | }
|
---|
490 |
|
---|
491 | /* cleanup */
|
---|
492 | smbcli_unlink(cli1->tree, fname);
|
---|
493 |
|
---|
494 | ud_cli_state.tctx = tctx;
|
---|
495 | ud_cli_state.cli1 = cli1;
|
---|
496 |
|
---|
497 | smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none,
|
---|
498 | &ud_cli_state);
|
---|
499 |
|
---|
500 | io.generic.level = RAW_OPEN_NTCREATEX;
|
---|
501 | io.ntcreatex.in.root_fid.fnum = 0;
|
---|
502 | io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
---|
503 | io.ntcreatex.in.alloc_size = 0;
|
---|
504 | io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
---|
505 | io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
|
---|
506 | NTCREATEX_SHARE_ACCESS_WRITE |
|
---|
507 | NTCREATEX_SHARE_ACCESS_DELETE;
|
---|
508 | io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
|
---|
509 | io.ntcreatex.in.create_options = 0;
|
---|
510 | io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
---|
511 | io.ntcreatex.in.security_flags = 0;
|
---|
512 | io.ntcreatex.in.fname = fname;
|
---|
513 |
|
---|
514 | /* cli1: open file with a batch oplock. */
|
---|
515 | io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
---|
516 | NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
---|
517 | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
---|
518 |
|
---|
519 | status = smb_raw_open(cli1->tree, tctx, &io);
|
---|
520 | CHECK_STATUS(status, NT_STATUS_OK);
|
---|
521 | fnum = io.ntcreatex.out.file.fnum;
|
---|
522 |
|
---|
523 | /* cli2: Try to unlink it, but block on the oplock */
|
---|
524 | torture_comment(tctx, "Try an unlink (should defer the open\n");
|
---|
525 | unl.unlink.in.pattern = fname;
|
---|
526 | unl.unlink.in.attrib = 0;
|
---|
527 | status = smb_raw_unlink(cli2->tree, &unl);
|
---|
528 |
|
---|
529 | done:
|
---|
530 | smb_raw_exit(cli1->session);
|
---|
531 | smb_raw_exit(cli2->session);
|
---|
532 | smbcli_deltree(cli1->tree, BASEDIR);
|
---|
533 | return ret;
|
---|
534 | }
|
---|
535 |
|
---|
536 | /*
|
---|
537 | basic testing of unlink calls
|
---|
538 | */
|
---|
539 | struct torture_suite *torture_raw_unlink(TALLOC_CTX *mem_ctx)
|
---|
540 | {
|
---|
541 | struct torture_suite *suite = torture_suite_create(mem_ctx, "unlink");
|
---|
542 |
|
---|
543 | torture_suite_add_1smb_test(suite, "unlink", test_unlink);
|
---|
544 | torture_suite_add_1smb_test(suite, "delete_on_close", test_delete_on_close);
|
---|
545 | torture_suite_add_2smb_test(suite, "unlink-defer", test_unlink_defer);
|
---|
546 |
|
---|
547 | return suite;
|
---|
548 | }
|
---|