Merge branch 'master' of ssh://git.samba.org/data/git/samba
[metze/samba/wip.git] / source4 / torture / raw / streams.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    test alternate data streams
5
6    Copyright (C) Andrew Tridgell 2004
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/locale.h"
24 #include "torture/torture.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "system/filesys.h"
27 #include "libcli/libcli.h"
28 #include "torture/util.h"
29
30 #define BASEDIR "\\teststreams"
31
32 #define CHECK_STATUS(status, correct) do { \
33         if (!NT_STATUS_EQUAL(status, correct)) { \
34                 printf("(%s) Incorrect status %s - should be %s\n", \
35                        __location__, nt_errstr(status), nt_errstr(correct)); \
36                 ret = false; \
37                 goto done; \
38         }} while (0)
39
40 #define CHECK_VALUE(v, correct) do { \
41         if ((v) != (correct)) { \
42                 printf("(%s) Incorrect value %s=%d - should be %d\n", \
43                        __location__, #v, (int)v, (int)correct); \
44                 ret = false; \
45         }} while (0)
46
47 #define CHECK_NTTIME(v, correct) do { \
48         if ((v) != (correct)) { \
49                 printf("(%s) Incorrect value %s=%llu - should be %llu\n", \
50                        __location__, #v, (unsigned long long)v, \
51                        (unsigned long long)correct); \
52                 ret = false; \
53         }} while (0)
54
55 #define CHECK_STR(v, correct) do { \
56         bool ok; \
57         if ((v) && !(correct)) { \
58                 ok = false; \
59         } else if (!(v) && (correct)) { \
60                 ok = false; \
61         } else if (!(v) && !(correct)) { \
62                 ok = true; \
63         } else if (strcmp((v), (correct)) == 0) { \
64                 ok = true; \
65         } else { \
66                 ok = false; \
67         } \
68         if (!ok) { \
69                 printf("(%s) Incorrect value %s='%s' - should be '%s'\n", \
70                        __location__, #v, (v)?(v):"NULL", \
71                        (correct)?(correct):"NULL"); \
72                 ret = false; \
73         }} while (0)
74
75 /*
76   check that a stream has the right contents
77 */
78 static bool check_stream(struct smbcli_state *cli, const char *location,
79                          TALLOC_CTX *mem_ctx,
80                          const char *fname, const char *sname, 
81                          const char *value)
82 {
83         int fnum;
84         const char *full_name;
85         uint8_t *buf;
86         ssize_t ret;
87
88         full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
89
90         fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
91
92         if (value == NULL) {
93                 if (fnum != -1) {
94                         printf("(%s) should have failed stream open of %s\n",
95                                location, full_name);
96                         return false;
97                 }
98                 return true;
99         }
100             
101         if (fnum == -1) {
102                 printf("(%s) Failed to open stream '%s' - %s\n",
103                        location, full_name, smbcli_errstr(cli->tree));
104                 return false;
105         }
106
107         buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
108         
109         ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
110         if (ret != strlen(value)) {
111                 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
112                        location, (long)strlen(value), full_name, (int)ret);
113                 return false;
114         }
115
116         if (memcmp(buf, value, strlen(value)) != 0) {
117                 printf("(%s) Bad data in stream\n", location);
118                 return false;
119         }
120
121         smbcli_close(cli->tree, fnum);
122         return true;
123 }
124
125 static int qsort_string(const void *v1, const void *v2)
126 {
127         char * const *s1 = v1;
128         char * const *s2 = v2;
129         return strcmp(*s1, *s2);
130 }
131
132 static int qsort_stream(const void *v1, const void *v2)
133 {
134         const struct stream_struct * s1 = v1;
135         const struct stream_struct * s2 = v2;
136         return strcmp(s1->stream_name.s, s2->stream_name.s);
137 }
138
139 static bool check_stream_list(struct smbcli_state *cli, const char *fname,
140                               int num_exp, const char **exp)
141 {
142         union smb_fileinfo finfo;
143         NTSTATUS status;
144         int i;
145         TALLOC_CTX *tmp_ctx = talloc_new(cli);
146         char **exp_sort;
147         struct stream_struct *stream_sort;
148         bool ret = false;
149
150         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
151         finfo.generic.in.file.path = fname;
152
153         status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
154         if (!NT_STATUS_IS_OK(status)) {
155                 d_fprintf(stderr, "(%s) smb_raw_pathinfo failed: %s\n",
156                           __location__, nt_errstr(status));
157                 goto fail;
158         }
159
160         if (finfo.stream_info.out.num_streams != num_exp) {
161                 d_fprintf(stderr, "(%s) expected %d streams, got %d\n",
162                           __location__, num_exp,
163                           finfo.stream_info.out.num_streams);
164                 goto fail;
165         }
166
167         if (num_exp == 0) {
168                 ret = true;
169                 goto fail;
170         }
171
172         exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
173
174         if (exp_sort == NULL) {
175                 goto fail;
176         }
177
178         qsort(exp_sort, num_exp, sizeof(*exp_sort), qsort_string);
179
180         stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
181                                     finfo.stream_info.out.num_streams *
182                                     sizeof(*stream_sort));
183
184         if (stream_sort == NULL) {
185                 goto fail;
186         }
187
188         qsort(stream_sort, finfo.stream_info.out.num_streams,
189               sizeof(*stream_sort), qsort_stream);
190
191         for (i=0; i<num_exp; i++) {
192                 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
193                         d_fprintf(stderr, "(%s) expected stream name %s, got "
194                                   "%s\n", __location__, exp_sort[i],
195                                   stream_sort[i].stream_name.s);
196                         goto fail;
197                 }
198         }
199
200         ret = true;
201  fail:
202         talloc_free(tmp_ctx);
203         return ret;
204 }
205
206 /*
207   test bahavior of streams on directories
208 */
209 static bool test_stream_dir(struct torture_context *tctx,
210                            struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
211 {
212         NTSTATUS status;
213         union smb_open io;
214         const char *fname = BASEDIR "\\stream.txt";
215         const char *sname1;
216         bool ret = true;
217         const char *basedir_data;
218
219         basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", BASEDIR);
220         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
221
222         printf("(%s) opening non-existant directory stream\n", __location__);
223         io.generic.level = RAW_OPEN_NTCREATEX;
224         io.ntcreatex.in.root_fid = 0;
225         io.ntcreatex.in.flags = 0;
226         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
227         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
228         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
229         io.ntcreatex.in.share_access = 0;
230         io.ntcreatex.in.alloc_size = 0;
231         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
232         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
233         io.ntcreatex.in.security_flags = 0;
234         io.ntcreatex.in.fname = sname1;
235         status = smb_raw_open(cli->tree, mem_ctx, &io);
236         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
237
238         printf("(%s) opening basedir  stream\n", __location__);
239         io.generic.level = RAW_OPEN_NTCREATEX;
240         io.ntcreatex.in.root_fid = 0;
241         io.ntcreatex.in.flags = 0;
242         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
243         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
244         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
245         io.ntcreatex.in.share_access = 0;
246         io.ntcreatex.in.alloc_size = 0;
247         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
248         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
249         io.ntcreatex.in.security_flags = 0;
250         io.ntcreatex.in.fname = basedir_data;
251         status = smb_raw_open(cli->tree, mem_ctx, &io);
252         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
253
254         printf("(%s) opening basedir ::$DATA stream\n", __location__);
255         io.generic.level = RAW_OPEN_NTCREATEX;
256         io.ntcreatex.in.root_fid = 0;
257         io.ntcreatex.in.flags = 0x10;
258         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
259         io.ntcreatex.in.create_options = 0;
260         io.ntcreatex.in.file_attr = 0;
261         io.ntcreatex.in.share_access = 0;
262         io.ntcreatex.in.alloc_size = 0;
263         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
264         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
265         io.ntcreatex.in.security_flags = 0;
266         io.ntcreatex.in.fname = basedir_data;
267         status = smb_raw_open(cli->tree, mem_ctx, &io);
268         CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
269
270         printf("(%s) list the streams on the basedir\n", __location__);
271         ret &= check_stream_list(cli, BASEDIR, 0, NULL);
272 done:
273         return ret;
274 }
275
276 /*
277   test basic behavior of streams on directories
278 */
279 static bool test_stream_io(struct torture_context *tctx,
280                            struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
281 {
282         NTSTATUS status;
283         union smb_open io;
284         const char *fname = BASEDIR "\\stream.txt";
285         const char *sname1, *sname2;
286         bool ret = true;
287         int fnum = -1;
288         ssize_t retsize;
289
290         const char *one[] = { "::$DATA" };
291         const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
292         const char *three[] = { "::$DATA", ":Stream One:$DATA",
293                                 ":Second Stream:$DATA" };
294
295         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
296         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
297
298         printf("(%s) creating a stream on a non-existant file\n", __location__);
299         io.generic.level = RAW_OPEN_NTCREATEX;
300         io.ntcreatex.in.root_fid = 0;
301         io.ntcreatex.in.flags = 0;
302         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
303         io.ntcreatex.in.create_options = 0;
304         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
305         io.ntcreatex.in.share_access = 0;
306         io.ntcreatex.in.alloc_size = 0;
307         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
308         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
309         io.ntcreatex.in.security_flags = 0;
310         io.ntcreatex.in.fname = sname1;
311         status = smb_raw_open(cli->tree, mem_ctx, &io);
312         CHECK_STATUS(status, NT_STATUS_OK);
313         fnum = io.ntcreatex.out.file.fnum;
314
315         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One", NULL);
316
317         printf("(%s) check that open of base file is allowed\n", __location__);
318         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
319         io.ntcreatex.in.fname = fname;
320         status = smb_raw_open(cli->tree, mem_ctx, &io);
321         CHECK_STATUS(status, NT_STATUS_OK);
322         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
323
324         printf("(%s) writing to stream\n", __location__);
325         retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
326         CHECK_VALUE(retsize, 9);
327
328         smbcli_close(cli->tree, fnum);
329
330         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One", "test data");
331
332         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
333         io.ntcreatex.in.fname = sname1;
334         status = smb_raw_open(cli->tree, mem_ctx, &io);
335         CHECK_STATUS(status, NT_STATUS_OK);
336         fnum = io.ntcreatex.out.file.fnum;
337
338         printf("(%s) modifying stream\n", __location__);
339         retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
340         CHECK_VALUE(retsize, 10);
341
342         smbcli_close(cli->tree, fnum);
343
344         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One:$FOO", NULL);
345
346         printf("(%s) creating a stream2 on a existing file\n", __location__);
347         io.ntcreatex.in.fname = sname2;
348         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
349         status = smb_raw_open(cli->tree, mem_ctx, &io);
350         CHECK_STATUS(status, NT_STATUS_OK);
351         fnum = io.ntcreatex.out.file.fnum;
352
353         printf("(%s) modifying stream\n", __location__);
354         retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
355         CHECK_VALUE(retsize, 13);
356
357         smbcli_close(cli->tree, fnum);
358
359         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One", "test MORE DATA ");
360         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One:$DATA", "test MORE DATA ");
361         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One:", NULL);
362         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream", "SECOND STREAM");
363         if (!torture_setting_bool(tctx, "samba4", false)) {
364                 ret &= check_stream(cli, __location__, mem_ctx, fname,
365                                     "SECOND STREAM:$DATA", "SECOND STREAM");
366         }
367         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream:$DATA", "SECOND STREAM");
368         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream:", NULL);
369         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream:$FOO", NULL);
370
371         check_stream_list(cli, fname, 3, three);
372
373         printf("(%s) deleting stream\n", __location__);
374         status = smbcli_unlink(cli->tree, sname1);
375         CHECK_STATUS(status, NT_STATUS_OK);
376
377         check_stream_list(cli, fname, 2, two);
378
379         printf("(%s) delete a stream via delete-on-close\n", __location__);
380         io.ntcreatex.in.fname = sname2;
381         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
382         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
383         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
384         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
385
386         status = smb_raw_open(cli->tree, mem_ctx, &io);
387         CHECK_STATUS(status, NT_STATUS_OK);
388         fnum = io.ntcreatex.out.file.fnum;
389         
390         smbcli_close(cli->tree, fnum);
391         status = smbcli_unlink(cli->tree, sname2);
392         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
393
394         check_stream_list(cli, fname, 1, one);
395
396         if (!torture_setting_bool(tctx, "samba4", false)) {
397                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
398                 io.ntcreatex.in.fname = sname1;
399                 status = smb_raw_open(cli->tree, mem_ctx, &io);
400                 CHECK_STATUS(status, NT_STATUS_OK);
401                 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
402                 io.ntcreatex.in.fname = sname2;
403                 status = smb_raw_open(cli->tree, mem_ctx, &io);
404                 CHECK_STATUS(status, NT_STATUS_OK);
405                 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
406         }
407
408         printf("(%s) deleting file\n", __location__);
409         status = smbcli_unlink(cli->tree, fname);
410         CHECK_STATUS(status, NT_STATUS_OK);
411
412 done:
413         smbcli_close(cli->tree, fnum);
414         return ret;
415 }
416
417 /*
418   test stream sharemodes
419 */
420 static bool test_stream_sharemodes(struct torture_context *tctx,
421                                    struct smbcli_state *cli,
422                                    TALLOC_CTX *mem_ctx)
423 {
424         NTSTATUS status;
425         union smb_open io;
426         const char *fname = BASEDIR "\\stream.txt";
427         const char *sname1, *sname2;
428         bool ret = true;
429         int fnum1 = -1;
430         int fnum2 = -1;
431
432         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
433         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
434
435         printf("(%s) testing stream share mode conflicts\n", __location__);
436         io.generic.level = RAW_OPEN_NTCREATEX;
437         io.ntcreatex.in.root_fid = 0;
438         io.ntcreatex.in.flags = 0;
439         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
440         io.ntcreatex.in.create_options = 0;
441         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
442         io.ntcreatex.in.share_access = 0;
443         io.ntcreatex.in.alloc_size = 0;
444         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
445         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
446         io.ntcreatex.in.security_flags = 0;
447         io.ntcreatex.in.fname = sname1;
448
449         status = smb_raw_open(cli->tree, mem_ctx, &io);
450         CHECK_STATUS(status, NT_STATUS_OK);
451         fnum1 = io.ntcreatex.out.file.fnum;
452
453         /*
454          * A different stream does not give a sharing violation
455          */
456
457         io.ntcreatex.in.fname = sname2;
458         status = smb_raw_open(cli->tree, mem_ctx, &io);
459         CHECK_STATUS(status, NT_STATUS_OK);
460         fnum2 = io.ntcreatex.out.file.fnum;
461
462         /*
463          * ... whereas the same stream does with unchanged access/share_access
464          * flags
465          */
466
467         io.ntcreatex.in.fname = sname1;
468         io.ntcreatex.in.open_disposition = 0;
469         status = smb_raw_open(cli->tree, mem_ctx, &io);
470         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
471
472         io.ntcreatex.in.fname = sname2;
473         status = smb_raw_open(cli->tree, mem_ctx, &io);
474         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
475
476 done:
477         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
478         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
479         status = smbcli_unlink(cli->tree, fname);
480         return ret;
481 }
482
483 /* 
484  *  Test FILE_SHARE_DELETE on streams
485  *
486  * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
487  * with SEC_STD_DELETE.
488  *
489  * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
490  * be opened with SEC_STD_DELETE.
491  *
492  * A stream held open with FILE_SHARE_DELETE allows the file to be
493  * deleted. After the main file is deleted, access to the open file descriptor
494  * still works, but all name-based access to both the main file as well as the
495  * stream is denied with DELETE ending.
496  *
497  * This means, an open of the main file with SEC_STD_DELETE should walk all
498  * streams and also open them with SEC_STD_DELETE. If any of these opens gives
499  * SHARING_VIOLATION, the main open fails.
500  *
501  * Closing the main file after delete_on_close has been set does not really
502  * unlink it but leaves the corresponding share mode entry with
503  * delete_on_close being set around until all streams are closed.
504  *
505  * Opening a stream must also look at the main file's share mode entry, look
506  * at the delete_on_close bit and potentially return DELETE_PENDING.
507  */
508
509 static bool test_stream_delete(struct torture_context *tctx,
510                                struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
511 {
512         NTSTATUS status;
513         union smb_open io;
514         const char *fname = BASEDIR "\\stream.txt";
515         const char *sname1;
516         bool ret = true;
517         int fnum = -1;
518         uint8_t buf[9];
519         ssize_t retsize;
520         union smb_fileinfo finfo;
521
522         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
523
524         printf("(%s) opening non-existant file stream\n", __location__);
525         io.generic.level = RAW_OPEN_NTCREATEX;
526         io.ntcreatex.in.root_fid = 0;
527         io.ntcreatex.in.flags = 0;
528         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
529         io.ntcreatex.in.create_options = 0;
530         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
531         io.ntcreatex.in.share_access = 0;
532         io.ntcreatex.in.alloc_size = 0;
533         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
534         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
535         io.ntcreatex.in.security_flags = 0;
536         io.ntcreatex.in.fname = sname1;
537
538         status = smb_raw_open(cli->tree, mem_ctx, &io);
539         CHECK_STATUS(status, NT_STATUS_OK);
540         fnum = io.ntcreatex.out.file.fnum;
541
542         retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
543         CHECK_VALUE(retsize, 9);
544
545         /*
546          * One stream opened without FILE_SHARE_DELETE prevents the main file
547          * to be deleted or even opened with DELETE access
548          */
549
550         status = smbcli_unlink(cli->tree, fname);
551         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
552
553         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
554         io.ntcreatex.in.fname = fname;
555         io.ntcreatex.in.access_mask = SEC_STD_DELETE;
556         status = smb_raw_open(cli->tree, mem_ctx, &io);
557         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
558
559         smbcli_close(cli->tree, fnum);
560
561         /*
562          * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
563          */
564
565         io.ntcreatex.in.fname = sname1;
566         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
567         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
568         status = smb_raw_open(cli->tree, mem_ctx, &io);
569         CHECK_STATUS(status, NT_STATUS_OK);
570         fnum = io.ntcreatex.out.file.fnum;
571
572         status = smbcli_unlink(cli->tree, fname);
573         CHECK_STATUS(status, NT_STATUS_OK);
574
575         /*
576          * file access still works on the stream while the main file is closed
577          */
578
579         retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
580         CHECK_VALUE(retsize, 9);
581
582         finfo.generic.level = RAW_FILEINFO_STANDARD;
583         finfo.generic.in.file.path = fname;
584
585         /*
586          * name-based access to both the main file and the stream does not
587          * work anymore but gives DELETE_PENDING
588          */
589
590         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
591         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
592
593         /*
594          * older S3 doesn't do this
595          */
596         finfo.generic.in.file.path = sname1;
597         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
598         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
599
600         /*
601          * fd-based qfileinfo on the stream still works, the stream does not
602          * have the delete-on-close bit set. This could mean that open on the
603          * stream first opens the main file
604          */
605
606         finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
607         finfo.all_info.in.file.fnum = fnum;
608
609         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
610         CHECK_STATUS(status, NT_STATUS_OK);
611         /* w2k and w2k3 return 0 and w2k8 returns 1
612         CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
613         */
614
615         smbcli_close(cli->tree, fnum);
616
617         /*
618          * After closing the stream the file is really gone.
619          */
620
621         finfo.generic.in.file.path = fname;
622         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
623         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
624
625         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA
626                 |SEC_STD_DELETE;
627         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
628         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
629         status = smb_raw_open(cli->tree, mem_ctx, &io);
630         CHECK_STATUS(status, NT_STATUS_OK);
631         fnum = io.ntcreatex.out.file.fnum;
632
633         finfo.generic.in.file.path = fname;
634         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
635         CHECK_STATUS(status, NT_STATUS_OK);
636
637         smbcli_close(cli->tree, fnum);
638
639         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
640         CHECK_STATUS(status, NT_STATUS_OK);
641 done:
642         smbcli_close(cli->tree, fnum);
643         return ret;
644 }
645
646 /*
647   test stream names
648 */
649 static bool test_stream_names(struct torture_context *tctx,
650                               struct smbcli_state *cli,
651                               TALLOC_CTX *mem_ctx)
652 {
653         NTSTATUS status;
654         union smb_open io;
655         union smb_fileinfo finfo;
656         union smb_fileinfo stinfo;
657         union smb_setfileinfo sinfo;
658         const char *fname = BASEDIR "\\stream_names.txt";
659         const char *sname1, *sname1b, *sname1c, *sname1d;
660         const char *sname2, *snamew, *snamew2;
661         const char *snamer1, *snamer2;
662         bool ret = true;
663         int fnum1 = -1;
664         int fnum2 = -1;
665         int fnum3 = -1;
666         int i;
667         const char *four[4] = {
668                 "::$DATA",
669                 ":\x05Stream\n One:$DATA",
670                 ":MStream Two:$DATA",
671                 ":?Stream*:$DATA"
672         };
673         const char *five1[5] = {
674                 "::$DATA",
675                 ":\x05Stream\n One:$DATA",
676                 ":BeforeRename:$DATA",
677                 ":MStream Two:$DATA",
678                 ":?Stream*:$DATA"
679         };
680         const char *five2[5] = {
681                 "::$DATA",
682                 ":\x05Stream\n One:$DATA",
683                 ":AfterRename:$DATA",
684                 ":MStream Two:$DATA",
685                 ":?Stream*:$DATA"
686         };
687
688         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
689         sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
690         sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
691         sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
692         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
693         snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
694         snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
695         snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "BeforeRename");
696         snamer2 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "AfterRename");
697
698         printf("(%s) testing stream names\n", __location__);
699         io.generic.level = RAW_OPEN_NTCREATEX;
700         io.ntcreatex.in.root_fid = 0;
701         io.ntcreatex.in.flags = 0;
702         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
703         io.ntcreatex.in.create_options = 0;
704         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
705         io.ntcreatex.in.share_access = 0;
706         io.ntcreatex.in.alloc_size = 0;
707         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
708         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
709         io.ntcreatex.in.security_flags = 0;
710         io.ntcreatex.in.fname = sname1;
711
712         status = smb_raw_open(cli->tree, mem_ctx, &io);
713         CHECK_STATUS(status, NT_STATUS_OK);
714         fnum1 = io.ntcreatex.out.file.fnum;
715
716         /*
717          * A different stream does not give a sharing violation
718          */
719
720         io.ntcreatex.in.fname = sname2;
721         status = smb_raw_open(cli->tree, mem_ctx, &io);
722         CHECK_STATUS(status, NT_STATUS_OK);
723         fnum2 = io.ntcreatex.out.file.fnum;
724
725         /*
726          * ... whereas the same stream does with unchanged access/share_access
727          * flags
728          */
729
730         io.ntcreatex.in.fname = sname1;
731         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
732         status = smb_raw_open(cli->tree, mem_ctx, &io);
733         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
734
735         io.ntcreatex.in.fname = sname1b;
736         status = smb_raw_open(cli->tree, mem_ctx, &io);
737         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
738
739         io.ntcreatex.in.fname = sname1c;
740         status = smb_raw_open(cli->tree, mem_ctx, &io);
741         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
742                 /* w2k returns INVALID_PARAMETER */
743                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
744         } else {
745                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
746         }
747
748         io.ntcreatex.in.fname = sname1d;
749         status = smb_raw_open(cli->tree, mem_ctx, &io);
750         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
751                 /* w2k returns INVALID_PARAMETER */
752                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
753         } else {
754                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
755         }
756
757         io.ntcreatex.in.fname = sname2;
758         status = smb_raw_open(cli->tree, mem_ctx, &io);
759         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
760
761         io.ntcreatex.in.fname = snamew;
762         status = smb_raw_open(cli->tree, mem_ctx, &io);
763         CHECK_STATUS(status, NT_STATUS_OK);
764         fnum3 = io.ntcreatex.out.file.fnum;
765
766         io.ntcreatex.in.fname = snamew2;
767         status = smb_raw_open(cli->tree, mem_ctx, &io);
768         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
769
770         ret &= check_stream_list(cli, fname, 4, four);
771
772         smbcli_close(cli->tree, fnum1);
773         smbcli_close(cli->tree, fnum2);
774         smbcli_close(cli->tree, fnum3);
775
776         if (torture_setting_bool(tctx, "samba4", true)) {
777                 goto done;
778         }
779
780         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
781         finfo.generic.in.file.path = fname;
782         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
783         CHECK_STATUS(status, NT_STATUS_OK);
784
785         ret &= check_stream_list(cli, fname, 4, four);
786
787         for (i=0; i < 4; i++) {
788                 NTTIME write_time;
789                 uint64_t stream_size;
790                 char *path = talloc_asprintf(tctx, "%s%s",
791                                              fname, four[i]);
792
793                 char *rpath = talloc_strdup(path, path);
794                 char *p = strrchr(rpath, ':');
795                 /* eat :$DATA */
796                 *p = 0;
797                 p--;
798                 if (*p == ':') {
799                         /* eat ::$DATA */
800                         *p = 0;
801                 }
802                 printf("(%s): i[%u][%s]\n", __location__, i, path);
803                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
804                 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
805                                               SEC_FILE_WRITE_ATTRIBUTE |
806                                             SEC_RIGHTS_FILE_ALL;
807                 io.ntcreatex.in.fname = path;
808                 status = smb_raw_open(cli->tree, mem_ctx, &io);
809                 CHECK_STATUS(status, NT_STATUS_OK);
810                 fnum1 = io.ntcreatex.out.file.fnum;
811
812                 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
813                 finfo.generic.in.file.path = fname;
814                 status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
815                 CHECK_STATUS(status, NT_STATUS_OK);
816
817                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
818                 stinfo.generic.in.file.fnum = fnum1;
819                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
820                 CHECK_STATUS(status, NT_STATUS_OK);
821                 if (!torture_setting_bool(tctx, "samba3", false)) {
822                         CHECK_NTTIME(stinfo.all_info.out.create_time,
823                                      finfo.all_info.out.create_time);
824                         CHECK_NTTIME(stinfo.all_info.out.access_time,
825                                      finfo.all_info.out.access_time);
826                         CHECK_NTTIME(stinfo.all_info.out.write_time,
827                                      finfo.all_info.out.write_time);
828                         CHECK_NTTIME(stinfo.all_info.out.change_time,
829                                      finfo.all_info.out.change_time);
830                 }
831                 CHECK_VALUE(stinfo.all_info.out.attrib,
832                             finfo.all_info.out.attrib);
833                 CHECK_VALUE(stinfo.all_info.out.size,
834                             finfo.all_info.out.size);
835                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
836                             finfo.all_info.out.delete_pending);
837                 CHECK_VALUE(stinfo.all_info.out.directory,
838                             finfo.all_info.out.directory);
839                 CHECK_VALUE(stinfo.all_info.out.ea_size,
840                             finfo.all_info.out.ea_size);
841
842                 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
843                 stinfo.generic.in.file.fnum = fnum1;
844                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
845                 CHECK_STATUS(status, NT_STATUS_OK);
846                 if (!torture_setting_bool(tctx, "samba3", false)) {
847                         CHECK_STR(rpath, stinfo.name_info.out.fname.s);
848                 }
849
850                 write_time = finfo.all_info.out.write_time;
851                 write_time += i*1000000;
852                 write_time /= 1000000;
853                 write_time *= 1000000;
854
855                 ZERO_STRUCT(sinfo);
856                 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
857                 sinfo.basic_info.in.file.fnum = fnum1;
858                 sinfo.basic_info.in.write_time = write_time;
859                 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
860                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
861                 CHECK_STATUS(status, NT_STATUS_OK);
862
863                 stream_size = i*8192;
864
865                 ZERO_STRUCT(sinfo);
866                 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
867                 sinfo.end_of_file_info.in.file.fnum = fnum1;
868                 sinfo.end_of_file_info.in.size = stream_size;
869                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
870                 CHECK_STATUS(status, NT_STATUS_OK);
871
872                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
873                 stinfo.generic.in.file.fnum = fnum1;
874                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
875                 CHECK_STATUS(status, NT_STATUS_OK);
876                 if (!torture_setting_bool(tctx, "samba3", false)) {
877                         CHECK_NTTIME(stinfo.all_info.out.write_time,
878                                      write_time);
879                         CHECK_VALUE(stinfo.all_info.out.attrib,
880                                     finfo.all_info.out.attrib);
881                 }
882                 CHECK_VALUE(stinfo.all_info.out.size,
883                             stream_size);
884                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
885                             finfo.all_info.out.delete_pending);
886                 CHECK_VALUE(stinfo.all_info.out.directory,
887                             finfo.all_info.out.directory);
888                 CHECK_VALUE(stinfo.all_info.out.ea_size,
889                             finfo.all_info.out.ea_size);
890
891                 ret &= check_stream_list(cli, fname, 4, four);
892
893                 smbcli_close(cli->tree, fnum1);
894                 talloc_free(path);
895         }
896
897         printf("(%s): testing stream renames\n", __location__);
898         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
899         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
900                                       SEC_FILE_WRITE_ATTRIBUTE |
901                                     SEC_RIGHTS_FILE_ALL;
902         io.ntcreatex.in.fname = snamer1;
903         status = smb_raw_open(cli->tree, mem_ctx, &io);
904         CHECK_STATUS(status, NT_STATUS_OK);
905         fnum1 = io.ntcreatex.out.file.fnum;
906
907         ret &= check_stream_list(cli, fname, 5, five1);
908
909         ZERO_STRUCT(sinfo);
910         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
911         sinfo.rename_information.in.file.fnum = fnum1;
912         sinfo.rename_information.in.overwrite = true;
913         sinfo.rename_information.in.root_fid = 0;
914         sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
915         status = smb_raw_setfileinfo(cli->tree, &sinfo);
916         CHECK_STATUS(status, NT_STATUS_OK);
917
918         ret &= check_stream_list(cli, fname, 5, five2);
919
920         ZERO_STRUCT(sinfo);
921         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
922         sinfo.rename_information.in.file.fnum = fnum1;
923         sinfo.rename_information.in.overwrite = false;
924         sinfo.rename_information.in.root_fid = 0;
925         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
926         status = smb_raw_setfileinfo(cli->tree, &sinfo);
927         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
928
929         ret &= check_stream_list(cli, fname, 5, five2);
930
931         ZERO_STRUCT(sinfo);
932         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
933         sinfo.rename_information.in.file.fnum = fnum1;
934         sinfo.rename_information.in.overwrite = true;
935         sinfo.rename_information.in.root_fid = 0;
936         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
937         status = smb_raw_setfileinfo(cli->tree, &sinfo);
938         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
939
940         ret &= check_stream_list(cli, fname, 5, five2);
941
942         /* TODO: we need to test more rename combinations */
943
944 done:
945         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
946         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
947         if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
948         status = smbcli_unlink(cli->tree, fname);
949         return ret;
950 }
951
952 /*
953   test stream names
954 */
955 static bool test_stream_names2(struct torture_context *tctx,
956                                struct smbcli_state *cli,
957                                TALLOC_CTX *mem_ctx)
958 {
959         NTSTATUS status;
960         union smb_open io;
961         const char *fname = BASEDIR "\\stream_names2.txt";
962         bool ret = true;
963         int fnum1 = -1;
964         uint8_t i;
965
966         printf("(%s) testing stream names\n", __location__);
967         io.generic.level = RAW_OPEN_NTCREATEX;
968         io.ntcreatex.in.root_fid = 0;
969         io.ntcreatex.in.flags = 0;
970         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
971         io.ntcreatex.in.create_options = 0;
972         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
973         io.ntcreatex.in.share_access = 0;
974         io.ntcreatex.in.alloc_size = 0;
975         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
976         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
977         io.ntcreatex.in.security_flags = 0;
978         io.ntcreatex.in.fname = fname;
979         status = smb_raw_open(cli->tree, mem_ctx, &io);
980         CHECK_STATUS(status, NT_STATUS_OK);
981         fnum1 = io.ntcreatex.out.file.fnum;
982
983         for (i=0x01; i < 0x7F; i++) {
984                 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
985                                              fname, i, i);
986                 NTSTATUS expected;
987
988                 switch (i) {
989                 case '/':/*0x2F*/
990                 case ':':/*0x3A*/
991                 case '\\':/*0x5C*/
992                         expected = NT_STATUS_OBJECT_NAME_INVALID;
993                         break;
994                 default:
995                         expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
996                         break;
997                 }
998
999                 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1000                        __location__, fname, isprint(i)?(char)i:' ', i,
1001                        isprint(i)?"":" (not printable)",
1002                        nt_errstr(expected));
1003
1004                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1005                 io.ntcreatex.in.fname = path;
1006                 status = smb_raw_open(cli->tree, mem_ctx, &io);
1007                 CHECK_STATUS(status, expected);
1008
1009                 talloc_free(path);
1010         }
1011
1012 done:
1013         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1014         status = smbcli_unlink(cli->tree, fname);
1015         return ret;
1016 }
1017
1018 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1019         check_fnum = true; \
1020         call_name = #call; \
1021         sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1022         sfinfo.generic.in.file.fnum = fnum; \
1023         status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1024         if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1025                 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1026                         nt_errstr(status), nt_errstr(rightstatus)); \
1027                 ret = false; \
1028         } \
1029         finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1030         finfo1.generic.in.file.fnum = fnum; \
1031         status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1032         if (!NT_STATUS_IS_OK(status2)) { \
1033                 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1034                 ret = false; \
1035         }} while (0)
1036
1037 /*
1038   test stream renames
1039 */
1040 static bool test_stream_rename(struct torture_context *tctx,
1041                                    struct smbcli_state *cli,
1042                                    TALLOC_CTX *mem_ctx)
1043 {
1044         NTSTATUS status, status2;
1045         union smb_open io;
1046         const char *fname = BASEDIR "\\stream_rename.txt";
1047         const char *sname1, *sname2;
1048         union smb_fileinfo finfo1;
1049         union smb_setfileinfo sfinfo;
1050         bool ret = true;
1051         int fnum = -1;
1052         bool check_fnum;
1053         const char *call_name;
1054
1055         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
1056         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
1057
1058         printf("(%s) testing stream renames\n", __location__);
1059         io.generic.level = RAW_OPEN_NTCREATEX;
1060         io.ntcreatex.in.root_fid = 0;
1061         io.ntcreatex.in.flags = 0;
1062         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1063                                       SEC_FILE_WRITE_ATTRIBUTE |
1064                                     SEC_RIGHTS_FILE_ALL;
1065         io.ntcreatex.in.create_options = 0;
1066         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1067         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1068         io.ntcreatex.in.alloc_size = 0;
1069         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1070         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1071         io.ntcreatex.in.security_flags = 0;
1072         io.ntcreatex.in.fname = sname1;
1073
1074         /* Create two streams. */
1075         status = smb_raw_open(cli->tree, mem_ctx, &io);
1076         CHECK_STATUS(status, NT_STATUS_OK);
1077         fnum = io.ntcreatex.out.file.fnum;
1078         if (fnum != -1) smbcli_close(cli->tree, fnum);
1079
1080         io.ntcreatex.in.fname = sname2;
1081         status = smb_raw_open(cli->tree, mem_ctx, &io);
1082         CHECK_STATUS(status, NT_STATUS_OK);
1083         fnum = io.ntcreatex.out.file.fnum;
1084
1085         if (fnum != -1) smbcli_close(cli->tree, fnum);
1086
1087         /*
1088          * Open the second stream.
1089          */
1090
1091         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1092         status = smb_raw_open(cli->tree, mem_ctx, &io);
1093         CHECK_STATUS(status, NT_STATUS_OK);
1094         fnum = io.ntcreatex.out.file.fnum;
1095
1096         /*
1097          * Now rename the second stream onto the first.
1098          */
1099
1100         ZERO_STRUCT(sfinfo);
1101
1102         sfinfo.rename_information.in.overwrite = 1;
1103         sfinfo.rename_information.in.root_fid  = 0;
1104         sfinfo.rename_information.in.new_name  = ":Stream One";
1105         CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1106
1107 done:
1108         if (fnum != -1) smbcli_close(cli->tree, fnum);
1109         status = smbcli_unlink(cli->tree, fname);
1110         return ret;
1111 }
1112
1113
1114 /* 
1115    basic testing of streams calls
1116 */
1117 bool torture_raw_streams(struct torture_context *torture, 
1118                          struct smbcli_state *cli)
1119 {
1120         bool ret = true;
1121
1122         if (!torture_setup_dir(cli, BASEDIR)) {
1123                 return false;
1124         }
1125
1126         ret &= test_stream_dir(torture, cli, torture);
1127         smb_raw_exit(cli->session);
1128         ret &= test_stream_io(torture, cli, torture);
1129         smb_raw_exit(cli->session);
1130         ret &= test_stream_sharemodes(torture, cli, torture);
1131         smb_raw_exit(cli->session);
1132         ret &= test_stream_names(torture, cli, torture);
1133         smb_raw_exit(cli->session);
1134         ret &= test_stream_names2(torture, cli, torture);
1135         smb_raw_exit(cli->session);
1136         ret &= test_stream_rename(torture, cli, torture);
1137         smb_raw_exit(cli->session);
1138         if (!torture_setting_bool(torture, "samba4", false)) {
1139                 ret &= test_stream_delete(torture, cli, torture);
1140         }
1141
1142         smb_raw_exit(cli->session);
1143         smbcli_deltree(cli->tree, BASEDIR);
1144
1145         return ret;
1146 }