s4-smb: declare root_fid as a file handle
[ira/wip.git] / source4 / torture / raw / rename.c
1 /* 
2    Unix SMB/CIFS implementation.
3    rename 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 "libcli/raw/libcliraw.h"
23 #include "libcli/libcli.h"
24 #include "torture/util.h"
25
26 #define CHECK_STATUS(status, correct) do { \
27         if (!NT_STATUS_EQUAL(status, correct)) { \
28                 torture_result(tctx, TORTURE_FAIL, \
29                         "(%s) Incorrect status %s - should be %s\n", \
30                         __location__, nt_errstr(status), nt_errstr(correct)); \
31                 ret = false; \
32                 goto done; \
33         }} while (0)
34
35 #define CHECK_VALUE(v, correct) do { \
36         if ((v) != (correct)) { \
37                 torture_result(tctx, TORTURE_FAIL, \
38                         "(%s) Incorrect %s %d - should be %d\n", \
39                         __location__, #v, (int)v, (int)correct); \
40                 ret = false; \
41         }} while (0)
42
43 #define BASEDIR "\\testrename"
44
45 /*
46   test SMBmv ops
47 */
48 static bool test_mv(struct torture_context *tctx, 
49                                         struct smbcli_state *cli)
50 {
51         union smb_rename io;
52         NTSTATUS status;
53         bool ret = true;
54         int fnum = -1;
55         const char *fname1 = BASEDIR "\\test1.txt";
56         const char *fname2 = BASEDIR "\\test2.txt";
57         const char *Fname1 = BASEDIR "\\Test1.txt";
58         union smb_fileinfo finfo;
59         union smb_open op;
60
61         torture_comment(tctx, "Testing SMBmv\n");
62
63         if (!torture_setup_dir(cli, BASEDIR)) {
64                 return false;
65         }
66
67         torture_comment(tctx, "Trying simple rename\n");
68
69         op.generic.level = RAW_OPEN_NTCREATEX;
70         op.ntcreatex.in.root_fid.fnum = 0;
71         op.ntcreatex.in.flags = 0;
72         op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
73         op.ntcreatex.in.create_options = 0;
74         op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
75         op.ntcreatex.in.share_access = 
76                 NTCREATEX_SHARE_ACCESS_READ | 
77                 NTCREATEX_SHARE_ACCESS_WRITE;
78         op.ntcreatex.in.alloc_size = 0;
79         op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
80         op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
81         op.ntcreatex.in.security_flags = 0;
82         op.ntcreatex.in.fname = fname1;
83
84         status = smb_raw_open(cli->tree, tctx, &op);
85         CHECK_STATUS(status, NT_STATUS_OK);
86         fnum = op.ntcreatex.out.file.fnum;
87
88         io.generic.level = RAW_RENAME_RENAME;
89         io.rename.in.pattern1 = fname1;
90         io.rename.in.pattern2 = fname2;
91         io.rename.in.attrib = 0;
92         
93         torture_comment(tctx, "trying rename while first file open\n");
94         status = smb_raw_rename(cli->tree, &io);
95         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
96
97         smbcli_close(cli->tree, fnum);
98
99         op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
100         op.ntcreatex.in.share_access = 
101                 NTCREATEX_SHARE_ACCESS_DELETE | 
102                 NTCREATEX_SHARE_ACCESS_READ |
103                 NTCREATEX_SHARE_ACCESS_WRITE;
104         status = smb_raw_open(cli->tree, tctx, &op);
105         CHECK_STATUS(status, NT_STATUS_OK);
106         fnum = op.ntcreatex.out.file.fnum;
107
108         torture_comment(tctx, "trying rename while first file open with SHARE_ACCESS_DELETE\n");
109         status = smb_raw_rename(cli->tree, &io);
110         CHECK_STATUS(status, NT_STATUS_OK);
111
112         io.rename.in.pattern1 = fname2;
113         io.rename.in.pattern2 = fname1;
114         status = smb_raw_rename(cli->tree, &io);
115         CHECK_STATUS(status, NT_STATUS_OK);
116
117         torture_comment(tctx, "Trying case-changing rename\n");
118         io.rename.in.pattern1 = fname1;
119         io.rename.in.pattern2 = Fname1;
120         status = smb_raw_rename(cli->tree, &io);
121         CHECK_STATUS(status, NT_STATUS_OK);
122
123         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
124         finfo.all_info.in.file.path = fname1;
125         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
126         CHECK_STATUS(status, NT_STATUS_OK);
127         if (strcmp(finfo.all_info.out.fname.s, Fname1) != 0) {
128                 torture_warning(tctx, "(%s) Incorrect filename [%s] after case-changing "
129                        "rename, should be [%s]\n", __location__,
130                        finfo.all_info.out.fname.s, Fname1);
131         }
132
133         io.rename.in.pattern1 = fname1;
134         io.rename.in.pattern2 = fname2;
135
136         torture_comment(tctx, "trying rename while not open\n");
137         smb_raw_exit(cli->session);
138         status = smb_raw_rename(cli->tree, &io);
139         CHECK_STATUS(status, NT_STATUS_OK);
140         
141         torture_comment(tctx, "Trying self rename\n");
142         io.rename.in.pattern1 = fname2;
143         io.rename.in.pattern2 = fname2;
144         status = smb_raw_rename(cli->tree, &io);
145         CHECK_STATUS(status, NT_STATUS_OK);
146
147         io.rename.in.pattern1 = fname1;
148         io.rename.in.pattern2 = fname1;
149         status = smb_raw_rename(cli->tree, &io);
150         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
151
152
153         torture_comment(tctx, "trying wildcard rename\n");
154         io.rename.in.pattern1 = BASEDIR "\\*.txt";
155         io.rename.in.pattern2 = fname1;
156         
157         status = smb_raw_rename(cli->tree, &io);
158         CHECK_STATUS(status, NT_STATUS_OK);
159
160         torture_comment(tctx, "and again\n");
161         status = smb_raw_rename(cli->tree, &io);
162         CHECK_STATUS(status, NT_STATUS_OK);
163
164         torture_comment(tctx, "Trying extension change\n");
165         io.rename.in.pattern1 = BASEDIR "\\*.txt";
166         io.rename.in.pattern2 = BASEDIR "\\*.bak";
167         status = smb_raw_rename(cli->tree, &io);
168         CHECK_STATUS(status, NT_STATUS_OK);
169
170         status = smb_raw_rename(cli->tree, &io);
171         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
172
173         torture_comment(tctx, "Checking attrib handling\n");
174         torture_set_file_attribute(cli->tree, BASEDIR "\\test1.bak", FILE_ATTRIBUTE_HIDDEN);
175         io.rename.in.pattern1 = BASEDIR "\\test1.bak";
176         io.rename.in.pattern2 = BASEDIR "\\*.txt";
177         io.rename.in.attrib = 0;
178         status = smb_raw_rename(cli->tree, &io);
179         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
180
181         io.rename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
182         status = smb_raw_rename(cli->tree, &io);
183         CHECK_STATUS(status, NT_STATUS_OK);
184
185 done:
186         smbcli_close(cli->tree, fnum);
187         smb_raw_exit(cli->session);
188         smbcli_deltree(cli->tree, BASEDIR);
189         return ret;
190 }
191
192
193 static bool test_osxrename(struct torture_context *tctx,
194                            struct smbcli_state *cli)
195 {
196         union smb_rename io;
197         union smb_unlink io_un;
198         NTSTATUS status;
199         bool ret = true;
200         int fnum = -1;
201         const char *fname1 = BASEDIR "\\test1";
202         const char *FNAME1 = BASEDIR "\\TEST1";
203         union smb_fileinfo finfo;
204         union smb_open op;
205
206         torture_comment(tctx, "\nTesting OSX Rename\n");
207         if (!torture_setup_dir(cli, BASEDIR)) {
208                 return false;
209         }
210         op.generic.level = RAW_OPEN_NTCREATEX;
211         op.ntcreatex.in.root_fid.fnum = 0;
212         op.ntcreatex.in.flags = 0;
213         op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
214         op.ntcreatex.in.create_options = 0;
215         op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
216         op.ntcreatex.in.share_access =
217                 NTCREATEX_SHARE_ACCESS_READ |
218                 NTCREATEX_SHARE_ACCESS_WRITE;
219         op.ntcreatex.in.alloc_size = 0;
220         op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
221         op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
222         op.ntcreatex.in.security_flags = 0;
223         op.ntcreatex.in.fname = fname1;
224
225         status = smb_raw_open(cli->tree, tctx, &op);
226         CHECK_STATUS(status, NT_STATUS_OK);
227         fnum = op.ntcreatex.out.file.fnum;
228
229         io.generic.level = RAW_RENAME_RENAME;
230         io.rename.in.attrib = 0;
231
232         smbcli_close(cli->tree, fnum);
233
234         /* Rename by changing case. First check for the
235          * existence of the file with the "newname".
236          * If we find one and both the output and input are same case,
237          * delete it. */
238
239         torture_comment(tctx, "Checking os X rename (case changing)\n");
240
241         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
242         finfo.all_info.in.file.path = FNAME1;
243         torture_comment(tctx, "Looking for file %s \n",FNAME1);
244         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
245
246         if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
247                 torture_comment(tctx, "Name of the file found %s \n", finfo.all_info.out.fname.s);
248                 if (strcmp(finfo.all_info.out.fname.s, finfo.all_info.in.file.path) == 0) {
249                         /* If file is found with the same case delete it */
250                         torture_comment(tctx, "Deleting File %s \n", finfo.all_info.out.fname.s);
251                         io_un.unlink.in.pattern = finfo.all_info.out.fname.s;
252                         io_un.unlink.in.attrib = 0;
253                         status = smb_raw_unlink(cli->tree, &io_un);
254                         CHECK_STATUS(status, NT_STATUS_OK);
255                 }
256         }
257
258         io.rename.in.pattern1 = fname1;
259         io.rename.in.pattern2 = FNAME1;
260         status = smb_raw_rename(cli->tree, &io);
261         CHECK_STATUS(status, NT_STATUS_OK);
262
263         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
264         finfo.all_info.in.file.path = fname1;
265         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
266         CHECK_STATUS(status, NT_STATUS_OK);
267         torture_comment(tctx, "File name after rename %s \n",finfo.all_info.out.fname.s);
268
269 done:
270         smbcli_close(cli->tree, fnum);
271         smb_raw_exit(cli->session);
272         smbcli_deltree(cli->tree, BASEDIR);
273         return ret;
274 }
275
276 /*
277   test SMBntrename ops
278 */
279 static bool test_ntrename(struct torture_context *tctx, 
280                                                   struct smbcli_state *cli)
281 {
282         union smb_rename io;
283         NTSTATUS status;
284         bool ret = true;
285         int fnum, i;
286         const char *fname1 = BASEDIR "\\test1.txt";
287         const char *fname2 = BASEDIR "\\test2.txt";
288         union smb_fileinfo finfo;
289
290         torture_comment(tctx, "Testing SMBntrename\n");
291
292         if (!torture_setup_dir(cli, BASEDIR)) {
293                 return false;
294         }
295
296         torture_comment(tctx, "Trying simple rename\n");
297
298         fnum = create_complex_file(cli, tctx, fname1);
299         
300         io.generic.level = RAW_RENAME_NTRENAME;
301         io.ntrename.in.old_name = fname1;
302         io.ntrename.in.new_name = fname2;
303         io.ntrename.in.attrib = 0;
304         io.ntrename.in.cluster_size = 0;
305         io.ntrename.in.flags = RENAME_FLAG_RENAME;
306         
307         status = smb_raw_rename(cli->tree, &io);
308         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
309         
310         smb_raw_exit(cli->session);
311         status = smb_raw_rename(cli->tree, &io);
312         CHECK_STATUS(status, NT_STATUS_OK);
313
314         torture_comment(tctx, "Trying self rename\n");
315         io.ntrename.in.old_name = fname2;
316         io.ntrename.in.new_name = fname2;
317         status = smb_raw_rename(cli->tree, &io);
318         CHECK_STATUS(status, NT_STATUS_OK);
319
320         io.ntrename.in.old_name = fname1;
321         io.ntrename.in.new_name = fname1;
322         status = smb_raw_rename(cli->tree, &io);
323         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
324
325         torture_comment(tctx, "trying wildcard rename\n");
326         io.ntrename.in.old_name = BASEDIR "\\*.txt";
327         io.ntrename.in.new_name = fname1;
328         
329         status = smb_raw_rename(cli->tree, &io);
330         CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
331
332         torture_comment(tctx, "Checking attrib handling\n");
333         torture_set_file_attribute(cli->tree, fname2, FILE_ATTRIBUTE_HIDDEN);
334         io.ntrename.in.old_name = fname2;
335         io.ntrename.in.new_name = fname1;
336         io.ntrename.in.attrib = 0;
337         status = smb_raw_rename(cli->tree, &io);
338         CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
339
340         io.ntrename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
341         status = smb_raw_rename(cli->tree, &io);
342         CHECK_STATUS(status, NT_STATUS_OK);
343
344         torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
345
346         torture_comment(tctx, "Checking hard link\n");
347         io.ntrename.in.old_name = fname1;
348         io.ntrename.in.new_name = fname2;
349         io.ntrename.in.attrib = 0;
350         io.ntrename.in.flags = RENAME_FLAG_HARD_LINK;
351         status = smb_raw_rename(cli->tree, &io);
352         CHECK_STATUS(status, NT_STATUS_OK);
353
354         torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
355
356         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
357         finfo.generic.in.file.path = fname2;
358         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
359         CHECK_STATUS(status, NT_STATUS_OK);
360         CHECK_VALUE(finfo.all_info.out.nlink, 2);
361         CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
362
363         finfo.generic.in.file.path = fname1;
364         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
365         CHECK_STATUS(status, NT_STATUS_OK);
366         CHECK_VALUE(finfo.all_info.out.nlink, 2);
367         CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
368
369         torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
370
371         smbcli_unlink(cli->tree, fname2);
372
373         finfo.generic.in.file.path = fname1;
374         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
375         CHECK_STATUS(status, NT_STATUS_OK);
376         CHECK_VALUE(finfo.all_info.out.nlink, 1);
377         CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
378
379         torture_comment(tctx, "Checking copy\n");
380         io.ntrename.in.old_name = fname1;
381         io.ntrename.in.new_name = fname2;
382         io.ntrename.in.attrib = 0;
383         io.ntrename.in.flags = RENAME_FLAG_COPY;
384         status = smb_raw_rename(cli->tree, &io);
385         CHECK_STATUS(status, NT_STATUS_OK);
386
387         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
388         finfo.generic.in.file.path = fname1;
389         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
390         CHECK_STATUS(status, NT_STATUS_OK);
391         CHECK_VALUE(finfo.all_info.out.nlink, 1);
392         CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
393
394         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
395         finfo.generic.in.file.path = fname2;
396         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
397         CHECK_STATUS(status, NT_STATUS_OK);
398         CHECK_VALUE(finfo.all_info.out.nlink, 1);
399         CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
400
401         torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
402
403         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
404         finfo.generic.in.file.path = fname2;
405         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
406         CHECK_STATUS(status, NT_STATUS_OK);
407         CHECK_VALUE(finfo.all_info.out.nlink, 1);
408         CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
409
410         finfo.generic.in.file.path = fname1;
411         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
412         CHECK_STATUS(status, NT_STATUS_OK);
413         CHECK_VALUE(finfo.all_info.out.nlink, 1);
414         CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
415
416         torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
417
418         smbcli_unlink(cli->tree, fname2);
419
420         finfo.generic.in.file.path = fname1;
421         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
422         CHECK_STATUS(status, NT_STATUS_OK);
423         CHECK_VALUE(finfo.all_info.out.nlink, 1);
424
425         torture_comment(tctx, "Checking invalid flags\n");
426         io.ntrename.in.old_name = fname1;
427         io.ntrename.in.new_name = fname2;
428         io.ntrename.in.attrib = 0;
429         io.ntrename.in.flags = 0;
430         status = smb_raw_rename(cli->tree, &io);
431         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
432
433         io.ntrename.in.flags = 300;
434         status = smb_raw_rename(cli->tree, &io);
435         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
436
437         io.ntrename.in.flags = 0x106;
438         status = smb_raw_rename(cli->tree, &io);
439         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
440
441         torture_comment(tctx, "Checking unknown field\n");
442         io.ntrename.in.old_name = fname1;
443         io.ntrename.in.new_name = fname2;
444         io.ntrename.in.attrib = 0;
445         io.ntrename.in.flags = RENAME_FLAG_RENAME;
446         io.ntrename.in.cluster_size = 0xff;
447         status = smb_raw_rename(cli->tree, &io);
448         CHECK_STATUS(status, NT_STATUS_OK);
449
450         torture_comment(tctx, "Trying RENAME_FLAG_MOVE_CLUSTER_INFORMATION\n");
451
452         io.ntrename.in.old_name = fname2;
453         io.ntrename.in.new_name = fname1;
454         io.ntrename.in.attrib = 0;
455         io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
456         io.ntrename.in.cluster_size = 1;
457         status = smb_raw_rename(cli->tree, &io);
458         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
459
460         io.ntrename.in.flags = RENAME_FLAG_COPY;
461         status = smb_raw_rename(cli->tree, &io);
462         CHECK_STATUS(status, NT_STATUS_OK);
463
464 #if 0
465         {
466                 char buf[16384];
467                 fnum = smbcli_open(cli->tree, fname1, O_RDWR, DENY_NONE);
468                 memset(buf, 1, sizeof(buf));
469                 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
470                 smbcli_close(cli->tree, fnum);
471
472                 fnum = smbcli_open(cli->tree, fname2, O_RDWR, DENY_NONE);
473                 memset(buf, 1, sizeof(buf));
474                 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)-1);
475                 smbcli_close(cli->tree, fnum);
476
477                 torture_all_info(cli->tree, fname1);
478                 torture_all_info(cli->tree, fname2);
479         }
480         
481
482         io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
483         status = smb_raw_rename(cli->tree, &io);
484         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
485
486         for (i=0;i<20000;i++) {
487                 io.ntrename.in.cluster_size = i;
488                 status = smb_raw_rename(cli->tree, &io);
489                 if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
490                         torture_warning(tctx, "i=%d status=%s\n", i, nt_errstr(status));
491                 }
492         }
493 #endif
494
495         torture_comment(tctx, "Checking other flags\n");
496
497         for (i=0;i<0xFFF;i++) {
498                 if (i == RENAME_FLAG_RENAME ||
499                     i == RENAME_FLAG_HARD_LINK ||
500                     i == RENAME_FLAG_COPY) {
501                         continue;
502                 }
503
504                 io.ntrename.in.old_name = fname2;
505                 io.ntrename.in.new_name = fname1;
506                 io.ntrename.in.flags = i;
507                 io.ntrename.in.attrib = 0;
508                 io.ntrename.in.cluster_size = 0;
509                 status = smb_raw_rename(cli->tree, &io);
510                 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
511                         torture_warning(tctx, "flags=0x%x status=%s\n", i, nt_errstr(status));
512                 }
513         }
514         
515 done:
516         smb_raw_exit(cli->session);
517         smbcli_deltree(cli->tree, BASEDIR);
518         return ret;
519 }
520
521 /*
522   test dir rename.
523 */
524 static bool test_dir_rename(struct torture_context *tctx, struct smbcli_state *cli)
525 {
526         union smb_open io;
527         union smb_rename ren_io;
528         NTSTATUS status;
529         const char *dname1 = BASEDIR "\\dir_for_rename";
530         const char *dname2 = BASEDIR "\\renamed_dir";
531         const char *dname1_long = BASEDIR "\\dir_for_rename_long";
532         const char *fname = BASEDIR "\\dir_for_rename\\file.txt";
533         const char *sname = BASEDIR "\\renamed_dir:a stream:$DATA";
534         bool ret = true;
535         int fnum = -1;
536
537         torture_comment(tctx, "Checking rename on a directory containing an open file.\n");
538
539         if (!torture_setup_dir(cli, BASEDIR)) {
540                 return false;
541         }
542
543         /* create a directory */
544         smbcli_rmdir(cli->tree, dname1);
545         smbcli_rmdir(cli->tree, dname2);
546         smbcli_rmdir(cli->tree, dname1_long);
547         smbcli_unlink(cli->tree, dname1);
548         smbcli_unlink(cli->tree, dname2);
549         smbcli_unlink(cli->tree, dname1_long);
550
551         ZERO_STRUCT(io);
552         io.generic.level = RAW_OPEN_NTCREATEX;
553         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
554         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
555         io.ntcreatex.in.alloc_size = 0;
556         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
557         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
558         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
559         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
560         io.ntcreatex.in.fname = dname1;
561         status = smb_raw_open(cli->tree, tctx, &io);
562         CHECK_STATUS(status, NT_STATUS_OK);
563
564         fnum = io.ntcreatex.out.file.fnum;
565         smbcli_close(cli->tree, fnum);
566
567         /* create the longname directory */
568         io.ntcreatex.in.fname = dname1_long;
569         status = smb_raw_open(cli->tree, tctx, &io);
570         CHECK_STATUS(status, NT_STATUS_OK);
571
572         fnum = io.ntcreatex.out.file.fnum;
573         smbcli_close(cli->tree, fnum);
574
575         /* Now create and hold open a file. */
576         ZERO_STRUCT(io);
577
578         io.generic.level = RAW_OPEN_NTCREATEX;
579         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
580         io.ntcreatex.in.root_fid.fnum = 0;
581         io.ntcreatex.in.alloc_size = 0;
582         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
583         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
584         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
585         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
586         io.ntcreatex.in.create_options = 0;
587         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
588         io.ntcreatex.in.security_flags = 0;
589         io.ntcreatex.in.fname = fname;
590
591         /* Create the file. */
592
593         status = smb_raw_open(cli->tree, tctx, &io);
594         CHECK_STATUS(status, NT_STATUS_OK);
595         fnum = io.ntcreatex.out.file.fnum;
596
597         /* Now try and rename the directory. */
598
599         ZERO_STRUCT(ren_io);
600         ren_io.generic.level = RAW_RENAME_RENAME;
601         ren_io.rename.in.pattern1 = dname1;
602         ren_io.rename.in.pattern2 = dname2;
603         ren_io.rename.in.attrib = 0;
604         
605         status = smb_raw_rename(cli->tree, &ren_io);
606         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
607
608         /* Close the file and try the rename. */
609         smbcli_close(cli->tree, fnum);
610
611         status = smb_raw_rename(cli->tree, &ren_io);
612         CHECK_STATUS(status, NT_STATUS_OK);
613
614         /*
615          * Now try just holding a second handle on the directory and holding
616          * it open across a rename.  This should be allowed.
617          */
618         io.ntcreatex.in.fname = dname2;
619         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
620
621         io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL |
622             SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_EA | SEC_FILE_READ_DATA;
623
624         status = smb_raw_open(cli->tree, tctx, &io);
625         CHECK_STATUS(status, NT_STATUS_OK);
626         fnum = io.ntcreatex.out.file.fnum;
627
628         ren_io.generic.level = RAW_RENAME_RENAME;
629         ren_io.rename.in.pattern1 = dname2;
630         ren_io.rename.in.pattern2 = dname1;
631         ren_io.rename.in.attrib = 0;
632
633         status = smb_raw_rename(cli->tree, &ren_io);
634         CHECK_STATUS(status, NT_STATUS_OK);
635
636         /* close our handle to the directory. */
637         smbcli_close(cli->tree, fnum);
638
639         /* Open a handle on the long name, and then
640          * try a rename. This would catch a regression
641          * in bug #6781.
642          */
643         io.ntcreatex.in.fname = dname1_long;
644         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
645
646         io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL |
647             SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_EA | SEC_FILE_READ_DATA;
648
649         status = smb_raw_open(cli->tree, tctx, &io);
650         CHECK_STATUS(status, NT_STATUS_OK);
651         fnum = io.ntcreatex.out.file.fnum;
652
653         ren_io.generic.level = RAW_RENAME_RENAME;
654         ren_io.rename.in.pattern1 = dname1;
655         ren_io.rename.in.pattern2 = dname2;
656         ren_io.rename.in.attrib = 0;
657
658         status = smb_raw_rename(cli->tree, &ren_io);
659         CHECK_STATUS(status, NT_STATUS_OK);
660
661         /* close our handle to the longname directory. */
662         smbcli_close(cli->tree, fnum);
663
664         /*
665          * Now try opening a stream on the directory and holding it open
666          * across a rename.  This should be allowed.
667          */
668         io.ntcreatex.in.fname = sname;
669
670         status = smb_raw_open(cli->tree, tctx, &io);
671         CHECK_STATUS(status, NT_STATUS_OK);
672         fnum = io.ntcreatex.out.file.fnum;
673
674         ren_io.generic.level = RAW_RENAME_RENAME;
675         ren_io.rename.in.pattern1 = dname2;
676         ren_io.rename.in.pattern2 = dname1;
677         ren_io.rename.in.attrib = 0;
678
679         status = smb_raw_rename(cli->tree, &ren_io);
680         CHECK_STATUS(status, NT_STATUS_OK);
681
682 done:
683
684         if (fnum != -1) {
685                 smbcli_close(cli->tree, fnum);
686         }
687         smb_raw_exit(cli->session);
688         smbcli_deltree(cli->tree, BASEDIR);
689         return ret;
690 }
691
692 extern bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2);
693 extern bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1);
694
695 /* 
696    basic testing of rename calls
697 */
698 struct torture_suite *torture_raw_rename(TALLOC_CTX *mem_ctx)
699 {
700         struct torture_suite *suite = torture_suite_create(mem_ctx, "RENAME");
701
702         torture_suite_add_1smb_test(suite, "mv", test_mv);
703         /* test_trans2rename and test_nttransrename are actually in torture/raw/oplock.c to
704            use the handlers and macros there. */
705         torture_suite_add_2smb_test(suite, "trans2rename", test_trans2rename);
706         torture_suite_add_1smb_test(suite, "nttransrename", test_nttransrename);
707         torture_suite_add_1smb_test(suite, "ntrename", test_ntrename);
708         torture_suite_add_1smb_test(suite, "osxrename", test_osxrename);
709         torture_suite_add_1smb_test(suite, "directory rename", test_dir_rename);
710
711         return suite;
712 }