s4-smbtorture: Make test names lowercase and dot-separated.
[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 #include "lib/util/tsort.h"
30
31 #define BASEDIR "\\teststreams"
32
33 #define CHECK_STATUS(status, correct) \
34         torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
35
36 #define CHECK_VALUE(v, correct) \
37         torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
38
39 #define CHECK_NTTIME(v, correct) \
40         torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
41
42 #define CHECK_STR(v, correct) do { \
43         bool ok; \
44         if ((v) && !(correct)) { \
45                 ok = false; \
46         } else if (!(v) && (correct)) { \
47                 ok = false; \
48         } else if (!(v) && !(correct)) { \
49                 ok = true; \
50         } else if (strcmp((v), (correct)) == 0) { \
51                 ok = true; \
52         } else { \
53                 ok = false; \
54         } \
55         torture_assert(tctx,ok,\
56                        talloc_asprintf(tctx, "got '%s', expected '%s'",\
57                        (v)?(v):"NULL", (correct)?(correct):"NULL")); \
58 } while (0)
59
60 /*
61   check that a stream has the right contents
62 */
63 static bool check_stream(struct smbcli_state *cli, const char *location,
64                          TALLOC_CTX *mem_ctx,
65                          const char *fname, const char *sname, 
66                          const char *value)
67 {
68         int fnum;
69         const char *full_name;
70         uint8_t *buf;
71         ssize_t ret;
72
73         full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
74
75         fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
76
77         if (value == NULL) {
78                 if (fnum != -1) {
79                         printf("(%s) should have failed stream open of %s\n",
80                                location, full_name);
81                         return false;
82                 }
83                 return true;
84         }
85             
86         if (fnum == -1) {
87                 printf("(%s) Failed to open stream '%s' - %s\n",
88                        location, full_name, smbcli_errstr(cli->tree));
89                 return false;
90         }
91
92         buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
93         
94         ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
95         if (ret != strlen(value)) {
96                 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
97                        location, (long)strlen(value), full_name, (int)ret);
98                 return false;
99         }
100
101         if (memcmp(buf, value, strlen(value)) != 0) {
102                 printf("(%s) Bad data in stream\n", location);
103                 return false;
104         }
105
106         smbcli_close(cli->tree, fnum);
107         return true;
108 }
109
110 static int qsort_string(char * const *s1, char * const *s2)
111 {
112         return strcmp(*s1, *s2);
113 }
114
115 static int qsort_stream(const struct stream_struct *s1, const struct stream_struct *s2)
116 {
117         return strcmp(s1->stream_name.s, s2->stream_name.s);
118 }
119
120 static bool check_stream_list(struct torture_context *tctx,
121                               struct smbcli_state *cli, const char *fname,
122                               int num_exp, const char **exp)
123 {
124         union smb_fileinfo finfo;
125         NTSTATUS status;
126         int i;
127         TALLOC_CTX *tmp_ctx = talloc_new(cli);
128         char **exp_sort;
129         struct stream_struct *stream_sort;
130         bool ret = false;
131         int fail = -1;
132
133         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
134         finfo.generic.in.file.path = fname;
135
136         status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
137         CHECK_STATUS(status, NT_STATUS_OK);
138
139         CHECK_VALUE(finfo.stream_info.out.num_streams, num_exp);
140
141         if (num_exp == 0) {
142                 ret = true;
143                 goto done;
144         }
145
146         exp_sort = (char **)talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
147
148         if (exp_sort == NULL) {
149                 goto done;
150         }
151
152         TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
153
154         stream_sort = (struct stream_struct *)talloc_memdup(tmp_ctx,
155                                 finfo.stream_info.out.streams,
156                                 finfo.stream_info.out.num_streams *
157                                 sizeof(*stream_sort));
158
159         if (stream_sort == NULL) {
160                 goto done;
161         }
162
163         TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
164
165         for (i=0; i<num_exp; i++) {
166                 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
167                         fail = i;
168                         goto show_streams;
169                 }
170         }
171
172         ret = true;
173 done:
174         talloc_free(tmp_ctx);
175         return ret;
176
177 show_streams:
178         for (i=0; i<num_exp; i++) {
179                 torture_comment(tctx, "stream names '%s' '%s'\n",
180                                 exp_sort[i], stream_sort[i].stream_name.s);
181         }
182         CHECK_STR(stream_sort[fail].stream_name.s, exp_sort[fail]);
183         talloc_free(tmp_ctx);
184         return ret;
185 }
186
187 /*
188   test bahavior of streams on directories
189 */
190 static bool test_stream_dir(struct torture_context *tctx,
191                            struct smbcli_state *cli)
192 {
193         NTSTATUS status;
194         union smb_open io;
195         const char *fname = BASEDIR "\\stream.txt";
196         const char *sname1;
197         bool ret = true;
198         const char *basedir_data;
199
200         if (!torture_setup_dir(cli, BASEDIR)) {
201                 return false;
202         }
203
204         basedir_data = talloc_asprintf(tctx, "%s::$DATA", BASEDIR);
205         sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
206
207         printf("(%s) opening non-existant directory stream\n", __location__);
208         io.generic.level = RAW_OPEN_NTCREATEX;
209         io.ntcreatex.in.root_fid.fnum = 0;
210         io.ntcreatex.in.flags = 0;
211         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
212         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
213         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
214         io.ntcreatex.in.share_access = 0;
215         io.ntcreatex.in.alloc_size = 0;
216         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
217         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
218         io.ntcreatex.in.security_flags = 0;
219         io.ntcreatex.in.fname = sname1;
220         status = smb_raw_open(cli->tree, tctx, &io);
221         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
222
223         printf("(%s) opening basedir  stream\n", __location__);
224         io.generic.level = RAW_OPEN_NTCREATEX;
225         io.ntcreatex.in.root_fid.fnum = 0;
226         io.ntcreatex.in.flags = 0;
227         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
228         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
229         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
230         io.ntcreatex.in.share_access = 0;
231         io.ntcreatex.in.alloc_size = 0;
232         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
233         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
234         io.ntcreatex.in.security_flags = 0;
235         io.ntcreatex.in.fname = basedir_data;
236         status = smb_raw_open(cli->tree, tctx, &io);
237         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
238
239         printf("(%s) opening basedir ::$DATA stream\n", __location__);
240         io.generic.level = RAW_OPEN_NTCREATEX;
241         io.ntcreatex.in.root_fid.fnum = 0;
242         io.ntcreatex.in.flags = 0x10;
243         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
244         io.ntcreatex.in.create_options = 0;
245         io.ntcreatex.in.file_attr = 0;
246         io.ntcreatex.in.share_access = 0;
247         io.ntcreatex.in.alloc_size = 0;
248         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
249         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
250         io.ntcreatex.in.security_flags = 0;
251         io.ntcreatex.in.fname = basedir_data;
252         status = smb_raw_open(cli->tree, tctx, &io);
253         CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
254
255         printf("(%s) list the streams on the basedir\n", __location__);
256         ret &= check_stream_list(tctx, cli, BASEDIR, 0, NULL);
257 done:
258         smbcli_deltree(cli->tree, BASEDIR);
259         return ret;
260 }
261
262 /*
263   test basic behavior of streams on directories
264 */
265 static bool test_stream_io(struct torture_context *tctx,
266                            struct smbcli_state *cli)
267 {
268         NTSTATUS status;
269         union smb_open io;
270         const char *fname = BASEDIR "\\stream.txt";
271         const char *sname1, *sname2;
272         bool ret = true;
273         int fnum = -1;
274         ssize_t retsize;
275
276         const char *one[] = { "::$DATA" };
277         const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
278         const char *three[] = { "::$DATA", ":Stream One:$DATA",
279                                 ":Second Stream:$DATA" };
280
281         if (!torture_setup_dir(cli, BASEDIR)) {
282                 return false;
283         }
284
285         sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
286         sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
287
288         printf("(%s) creating a stream on a non-existant file\n", __location__);
289         io.generic.level = RAW_OPEN_NTCREATEX;
290         io.ntcreatex.in.root_fid.fnum = 0;
291         io.ntcreatex.in.flags = 0;
292         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
293         io.ntcreatex.in.create_options = 0;
294         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
295         io.ntcreatex.in.share_access = 0;
296         io.ntcreatex.in.alloc_size = 0;
297         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
298         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
299         io.ntcreatex.in.security_flags = 0;
300         io.ntcreatex.in.fname = sname1;
301         status = smb_raw_open(cli->tree, tctx, &io);
302         CHECK_STATUS(status, NT_STATUS_OK);
303         fnum = io.ntcreatex.out.file.fnum;
304
305         ret &= check_stream(cli, __location__, tctx, fname, "Stream One", NULL);
306
307         printf("(%s) check that open of base file is allowed\n", __location__);
308         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
309         io.ntcreatex.in.fname = fname;
310         status = smb_raw_open(cli->tree, tctx, &io);
311         CHECK_STATUS(status, NT_STATUS_OK);
312         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
313
314         printf("(%s) writing to stream\n", __location__);
315         retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
316         CHECK_VALUE(retsize, 9);
317
318         smbcli_close(cli->tree, fnum);
319
320         ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test data");
321
322         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
323         io.ntcreatex.in.fname = sname1;
324         status = smb_raw_open(cli->tree, tctx, &io);
325         CHECK_STATUS(status, NT_STATUS_OK);
326         fnum = io.ntcreatex.out.file.fnum;
327
328         printf("(%s) modifying stream\n", __location__);
329         retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
330         CHECK_VALUE(retsize, 10);
331
332         smbcli_close(cli->tree, fnum);
333
334         ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$FOO", NULL);
335
336         printf("(%s) creating a stream2 on a existing file\n", __location__);
337         io.ntcreatex.in.fname = sname2;
338         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
339         status = smb_raw_open(cli->tree, tctx, &io);
340         CHECK_STATUS(status, NT_STATUS_OK);
341         fnum = io.ntcreatex.out.file.fnum;
342
343         printf("(%s) modifying stream\n", __location__);
344         retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
345         CHECK_VALUE(retsize, 13);
346
347         smbcli_close(cli->tree, fnum);
348
349         ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test MORE DATA ");
350         ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$DATA", "test MORE DATA ");
351         ret &= check_stream(cli, __location__, tctx, fname, "Stream One:", NULL);
352         ret &= check_stream(cli, __location__, tctx, fname, "Second Stream", "SECOND STREAM");
353         ret &= check_stream(cli, __location__, tctx, fname,
354                             "SECOND STREAM:$DATA", "SECOND STREAM");
355         ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$DATA", "SECOND STREAM");
356         ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:", NULL);
357         ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$FOO", NULL);
358
359         check_stream_list(tctx, cli, fname, 3, three);
360
361         printf("(%s) deleting stream\n", __location__);
362         status = smbcli_unlink(cli->tree, sname1);
363         CHECK_STATUS(status, NT_STATUS_OK);
364
365         check_stream_list(tctx, cli, fname, 2, two);
366
367         printf("(%s) delete a stream via delete-on-close\n", __location__);
368         io.ntcreatex.in.fname = sname2;
369         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
370         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
371         io.ntcreatex.in.access_mask = SEC_STD_DELETE;
372         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
373
374         status = smb_raw_open(cli->tree, tctx, &io);
375         CHECK_STATUS(status, NT_STATUS_OK);
376         fnum = io.ntcreatex.out.file.fnum;
377         
378         smbcli_close(cli->tree, fnum);
379         status = smbcli_unlink(cli->tree, sname2);
380         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
381
382         check_stream_list(tctx, cli, fname, 1, one);
383
384         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
385         io.ntcreatex.in.fname = sname1;
386         status = smb_raw_open(cli->tree, tctx, &io);
387         CHECK_STATUS(status, NT_STATUS_OK);
388         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
389         io.ntcreatex.in.fname = sname2;
390         status = smb_raw_open(cli->tree, tctx, &io);
391         CHECK_STATUS(status, NT_STATUS_OK);
392         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
393
394         printf("(%s) deleting file\n", __location__);
395         status = smbcli_unlink(cli->tree, fname);
396         CHECK_STATUS(status, NT_STATUS_OK);
397
398 done:
399         smbcli_close(cli->tree, fnum);
400         smbcli_deltree(cli->tree, BASEDIR);
401         return ret;
402 }
403
404 /*
405   test stream sharemodes
406 */
407 static bool test_stream_sharemodes(struct torture_context *tctx,
408                                    struct smbcli_state *cli)
409 {
410         NTSTATUS status;
411         union smb_open io;
412         const char *fname = BASEDIR "\\stream.txt";
413         const char *sname1, *sname2;
414         bool ret = true;
415         int fnum1 = -1;
416         int fnum2 = -1;
417
418         if (!torture_setup_dir(cli, BASEDIR)) {
419                 return false;
420         }
421
422         sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
423         sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
424
425         printf("(%s) testing stream share mode conflicts\n", __location__);
426         io.generic.level = RAW_OPEN_NTCREATEX;
427         io.ntcreatex.in.root_fid.fnum = 0;
428         io.ntcreatex.in.flags = 0;
429         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
430         io.ntcreatex.in.create_options = 0;
431         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
432         io.ntcreatex.in.share_access = 0;
433         io.ntcreatex.in.alloc_size = 0;
434         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
435         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
436         io.ntcreatex.in.security_flags = 0;
437         io.ntcreatex.in.fname = sname1;
438
439         status = smb_raw_open(cli->tree, tctx, &io);
440         CHECK_STATUS(status, NT_STATUS_OK);
441         fnum1 = io.ntcreatex.out.file.fnum;
442
443         /*
444          * A different stream does not give a sharing violation
445          */
446
447         io.ntcreatex.in.fname = sname2;
448         status = smb_raw_open(cli->tree, tctx, &io);
449         CHECK_STATUS(status, NT_STATUS_OK);
450         fnum2 = io.ntcreatex.out.file.fnum;
451
452         /*
453          * ... whereas the same stream does with unchanged access/share_access
454          * flags
455          */
456
457         io.ntcreatex.in.fname = sname1;
458         io.ntcreatex.in.open_disposition = 0;
459         status = smb_raw_open(cli->tree, tctx, &io);
460         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
461
462         io.ntcreatex.in.fname = sname2;
463         status = smb_raw_open(cli->tree, tctx, &io);
464         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
465
466 done:
467         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
468         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
469         status = smbcli_unlink(cli->tree, fname);
470         smbcli_deltree(cli->tree, BASEDIR);
471         return ret;
472 }
473
474 /* 
475  *  Test FILE_SHARE_DELETE on streams
476  *
477  * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
478  * with SEC_STD_DELETE.
479  *
480  * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
481  * be opened with SEC_STD_DELETE.
482  *
483  * A stream held open with FILE_SHARE_DELETE allows the file to be
484  * deleted. After the main file is deleted, access to the open file descriptor
485  * still works, but all name-based access to both the main file as well as the
486  * stream is denied with DELETE ending.
487  *
488  * This means, an open of the main file with SEC_STD_DELETE should walk all
489  * streams and also open them with SEC_STD_DELETE. If any of these opens gives
490  * SHARING_VIOLATION, the main open fails.
491  *
492  * Closing the main file after delete_on_close has been set does not really
493  * unlink it but leaves the corresponding share mode entry with
494  * delete_on_close being set around until all streams are closed.
495  *
496  * Opening a stream must also look at the main file's share mode entry, look
497  * at the delete_on_close bit and potentially return DELETE_PENDING.
498  */
499
500 static bool test_stream_delete(struct torture_context *tctx,
501                                struct smbcli_state *cli)
502 {
503         NTSTATUS status;
504         union smb_open io;
505         const char *fname = BASEDIR "\\stream.txt";
506         const char *sname1;
507         bool ret = true;
508         int fnum = -1;
509         uint8_t buf[9];
510         ssize_t retsize;
511         union smb_fileinfo finfo;
512
513         if (!torture_setup_dir(cli, BASEDIR)) {
514                 return false;
515         }
516
517         sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
518
519         printf("(%s) opening non-existant file stream\n", __location__);
520         io.generic.level = RAW_OPEN_NTCREATEX;
521         io.ntcreatex.in.root_fid.fnum = 0;
522         io.ntcreatex.in.flags = 0;
523         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
524         io.ntcreatex.in.create_options = 0;
525         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
526         io.ntcreatex.in.share_access = 0;
527         io.ntcreatex.in.alloc_size = 0;
528         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
529         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
530         io.ntcreatex.in.security_flags = 0;
531         io.ntcreatex.in.fname = sname1;
532
533         status = smb_raw_open(cli->tree, tctx, &io);
534         CHECK_STATUS(status, NT_STATUS_OK);
535         fnum = io.ntcreatex.out.file.fnum;
536
537         retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
538         CHECK_VALUE(retsize, 9);
539
540         /*
541          * One stream opened without FILE_SHARE_DELETE prevents the main file
542          * to be deleted or even opened with DELETE access
543          */
544
545         status = smbcli_unlink(cli->tree, fname);
546         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
547
548         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
549         io.ntcreatex.in.fname = fname;
550         io.ntcreatex.in.access_mask = SEC_STD_DELETE;
551         status = smb_raw_open(cli->tree, tctx, &io);
552         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
553
554         smbcli_close(cli->tree, fnum);
555
556         /*
557          * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
558          */
559
560         io.ntcreatex.in.fname = sname1;
561         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
562         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
563         status = smb_raw_open(cli->tree, tctx, &io);
564         CHECK_STATUS(status, NT_STATUS_OK);
565         fnum = io.ntcreatex.out.file.fnum;
566
567         status = smbcli_unlink(cli->tree, fname);
568         CHECK_STATUS(status, NT_STATUS_OK);
569
570         /*
571          * file access still works on the stream while the main file is closed
572          */
573
574         retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
575         CHECK_VALUE(retsize, 9);
576
577         finfo.generic.level = RAW_FILEINFO_STANDARD;
578         finfo.generic.in.file.path = fname;
579
580         /*
581          * name-based access to both the main file and the stream does not
582          * work anymore but gives DELETE_PENDING
583          */
584
585         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
586         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
587
588         /*
589          * older S3 doesn't do this
590          */
591         finfo.generic.in.file.path = sname1;
592         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
593         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
594
595         /*
596          * fd-based qfileinfo on the stream still works, the stream does not
597          * have the delete-on-close bit set. This could mean that open on the
598          * stream first opens the main file
599          */
600
601         finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
602         finfo.all_info.in.file.fnum = fnum;
603
604         status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
605         CHECK_STATUS(status, NT_STATUS_OK);
606
607         /* w2k and w2k3 return 0 and w2k8 returns 1 */
608         if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) ||
609             TARGET_IS_SAMBA3(tctx)) {
610                 CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
611         } else {
612                 CHECK_VALUE(finfo.all_info.out.delete_pending, 1);
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, tctx, &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, tctx, &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, tctx, &finfo);
635         CHECK_STATUS(status, NT_STATUS_OK);
636
637         smbcli_close(cli->tree, fnum);
638
639         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
640         CHECK_STATUS(status, NT_STATUS_OK);
641 done:
642         smbcli_close(cli->tree, fnum);
643         smbcli_unlink(cli->tree, fname);
644         smbcli_deltree(cli->tree, BASEDIR);
645         return ret;
646 }
647
648 /*
649   test stream names
650 */
651 static bool test_stream_names(struct torture_context *tctx,
652                               struct smbcli_state *cli)
653 {
654         NTSTATUS status;
655         union smb_open io;
656         union smb_fileinfo finfo;
657         union smb_fileinfo stinfo;
658         union smb_setfileinfo sinfo;
659         const char *fname = BASEDIR "\\stream_names.txt";
660         const char *sname1, *sname1b, *sname1c, *sname1d;
661         const char *sname2, *snamew, *snamew2;
662         const char *snamer1, *snamer2;
663         bool ret = true;
664         int fnum1 = -1;
665         int fnum2 = -1;
666         int fnum3 = -1;
667         int i;
668         const char *four[4] = {
669                 "::$DATA",
670                 ":\x05Stream\n One:$DATA",
671                 ":MStream Two:$DATA",
672                 ":?Stream*:$DATA"
673         };
674         const char *five1[5] = {
675                 "::$DATA",
676                 ":\x05Stream\n One:$DATA",
677                 ":BeforeRename:$DATA",
678                 ":MStream Two:$DATA",
679                 ":?Stream*:$DATA"
680         };
681         const char *five2[5] = {
682                 "::$DATA",
683                 ":\x05Stream\n One:$DATA",
684                 ":AfterRename:$DATA",
685                 ":MStream Two:$DATA",
686                 ":?Stream*:$DATA"
687         };
688
689         if (!torture_setup_dir(cli, BASEDIR)) {
690                 return false;
691         }
692
693         sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
694         sname1b = talloc_asprintf(tctx, "%s:", sname1);
695         sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
696         sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
697         sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
698         snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
699         snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
700         snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
701         snamer2 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "AfterRename");
702
703         printf("(%s) testing stream names\n", __location__);
704         io.generic.level = RAW_OPEN_NTCREATEX;
705         io.ntcreatex.in.root_fid.fnum = 0;
706         io.ntcreatex.in.flags = 0;
707         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
708         io.ntcreatex.in.create_options = 0;
709         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
710         io.ntcreatex.in.share_access = 0;
711         io.ntcreatex.in.alloc_size = 0;
712         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
713         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
714         io.ntcreatex.in.security_flags = 0;
715         io.ntcreatex.in.fname = fname;
716
717         status = smb_raw_open(cli->tree, tctx, &io);
718         CHECK_STATUS(status, NT_STATUS_OK);
719         fnum1 = io.ntcreatex.out.file.fnum;
720
721         /*
722          * Make sure the create time of the streams are different from the
723          * base file.
724          */
725         sleep(2);
726         smbcli_close(cli->tree, fnum1);
727
728         io.generic.level = RAW_OPEN_NTCREATEX;
729         io.ntcreatex.in.root_fid.fnum = 0;
730         io.ntcreatex.in.flags = 0;
731         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
732         io.ntcreatex.in.create_options = 0;
733         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
734         io.ntcreatex.in.share_access = 0;
735         io.ntcreatex.in.alloc_size = 0;
736         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
737         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
738         io.ntcreatex.in.security_flags = 0;
739         io.ntcreatex.in.fname = sname1;
740
741         status = smb_raw_open(cli->tree, tctx, &io);
742         CHECK_STATUS(status, NT_STATUS_OK);
743         fnum1 = io.ntcreatex.out.file.fnum;
744
745         /*
746          * A different stream does not give a sharing violation
747          */
748
749         io.ntcreatex.in.fname = sname2;
750         status = smb_raw_open(cli->tree, tctx, &io);
751         CHECK_STATUS(status, NT_STATUS_OK);
752         fnum2 = io.ntcreatex.out.file.fnum;
753
754         /*
755          * ... whereas the same stream does with unchanged access/share_access
756          * flags
757          */
758
759         io.ntcreatex.in.fname = sname1;
760         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
761         status = smb_raw_open(cli->tree, tctx, &io);
762         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
763
764         io.ntcreatex.in.fname = sname1b;
765         status = smb_raw_open(cli->tree, tctx, &io);
766         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
767
768         io.ntcreatex.in.fname = sname1c;
769         status = smb_raw_open(cli->tree, tctx, &io);
770         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
771                 /* w2k returns INVALID_PARAMETER */
772                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
773         } else {
774                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
775         }
776
777         io.ntcreatex.in.fname = sname1d;
778         status = smb_raw_open(cli->tree, tctx, &io);
779         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
780                 /* w2k returns INVALID_PARAMETER */
781                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
782         } else {
783                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
784         }
785
786         io.ntcreatex.in.fname = sname2;
787         status = smb_raw_open(cli->tree, tctx, &io);
788         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
789
790         io.ntcreatex.in.fname = snamew;
791         status = smb_raw_open(cli->tree, tctx, &io);
792         CHECK_STATUS(status, NT_STATUS_OK);
793         fnum3 = io.ntcreatex.out.file.fnum;
794
795         io.ntcreatex.in.fname = snamew2;
796         status = smb_raw_open(cli->tree, tctx, &io);
797         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
798
799         ret &= check_stream_list(tctx, cli, fname, 4, four);
800
801         smbcli_close(cli->tree, fnum1);
802         smbcli_close(cli->tree, fnum2);
803         smbcli_close(cli->tree, fnum3);
804
805         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
806         finfo.generic.in.file.path = fname;
807         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
808         CHECK_STATUS(status, NT_STATUS_OK);
809
810         ret &= check_stream_list(tctx, cli, fname, 4, four);
811
812         for (i=0; i < 4; i++) {
813                 NTTIME write_time;
814                 uint64_t stream_size;
815                 char *path = talloc_asprintf(tctx, "%s%s",
816                                              fname, four[i]);
817
818                 char *rpath = talloc_strdup(path, path);
819                 char *p = strrchr(rpath, ':');
820                 /* eat :$DATA */
821                 *p = 0;
822                 p--;
823                 if (*p == ':') {
824                         /* eat ::$DATA */
825                         *p = 0;
826                 }
827                 printf("(%s): i[%u][%s]\n", __location__, i, path);
828                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
829                 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
830                                               SEC_FILE_WRITE_ATTRIBUTE |
831                                             SEC_RIGHTS_FILE_ALL;
832                 io.ntcreatex.in.fname = path;
833                 status = smb_raw_open(cli->tree, tctx, &io);
834                 CHECK_STATUS(status, NT_STATUS_OK);
835                 fnum1 = io.ntcreatex.out.file.fnum;
836
837                 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
838                 finfo.generic.in.file.path = fname;
839                 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
840                 CHECK_STATUS(status, NT_STATUS_OK);
841
842                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
843                 stinfo.generic.in.file.fnum = fnum1;
844                 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
845                 CHECK_STATUS(status, NT_STATUS_OK);
846                 if (!torture_setting_bool(tctx, "samba3", false)) {
847                         CHECK_NTTIME(stinfo.all_info.out.create_time,
848                                      finfo.all_info.out.create_time);
849                         CHECK_NTTIME(stinfo.all_info.out.access_time,
850                                      finfo.all_info.out.access_time);
851                         CHECK_NTTIME(stinfo.all_info.out.write_time,
852                                      finfo.all_info.out.write_time);
853                         CHECK_NTTIME(stinfo.all_info.out.change_time,
854                                      finfo.all_info.out.change_time);
855                 }
856                 CHECK_VALUE(stinfo.all_info.out.attrib,
857                             finfo.all_info.out.attrib);
858                 CHECK_VALUE(stinfo.all_info.out.size,
859                             finfo.all_info.out.size);
860                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
861                             finfo.all_info.out.delete_pending);
862                 CHECK_VALUE(stinfo.all_info.out.directory,
863                             finfo.all_info.out.directory);
864                 CHECK_VALUE(stinfo.all_info.out.ea_size,
865                             finfo.all_info.out.ea_size);
866
867                 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
868                 stinfo.generic.in.file.fnum = fnum1;
869                 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
870                 CHECK_STATUS(status, NT_STATUS_OK);
871                 if (!torture_setting_bool(tctx, "samba3", false)) {
872                         CHECK_STR(stinfo.name_info.out.fname.s, rpath);
873                 }
874
875                 write_time = finfo.all_info.out.write_time;
876                 write_time += i*1000000;
877                 write_time /= 1000000;
878                 write_time *= 1000000;
879
880                 ZERO_STRUCT(sinfo);
881                 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
882                 sinfo.basic_info.in.file.fnum = fnum1;
883                 sinfo.basic_info.in.write_time = write_time;
884                 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
885                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
886                 CHECK_STATUS(status, NT_STATUS_OK);
887
888                 stream_size = i*8192;
889
890                 ZERO_STRUCT(sinfo);
891                 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
892                 sinfo.end_of_file_info.in.file.fnum = fnum1;
893                 sinfo.end_of_file_info.in.size = stream_size;
894                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
895                 CHECK_STATUS(status, NT_STATUS_OK);
896
897                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
898                 stinfo.generic.in.file.fnum = fnum1;
899                 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
900                 CHECK_STATUS(status, NT_STATUS_OK);
901                 if (!torture_setting_bool(tctx, "samba3", false)) {
902                         CHECK_NTTIME(stinfo.all_info.out.write_time,
903                                      write_time);
904                         CHECK_VALUE(stinfo.all_info.out.attrib,
905                                     finfo.all_info.out.attrib);
906                 }
907                 CHECK_VALUE(stinfo.all_info.out.size,
908                             stream_size);
909                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
910                             finfo.all_info.out.delete_pending);
911                 CHECK_VALUE(stinfo.all_info.out.directory,
912                             finfo.all_info.out.directory);
913                 CHECK_VALUE(stinfo.all_info.out.ea_size,
914                             finfo.all_info.out.ea_size);
915
916                 ret &= check_stream_list(tctx, cli, fname, 4, four);
917
918                 smbcli_close(cli->tree, fnum1);
919                 talloc_free(path);
920         }
921
922         printf("(%s): testing stream renames\n", __location__);
923         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
924         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
925                                       SEC_FILE_WRITE_ATTRIBUTE |
926                                     SEC_RIGHTS_FILE_ALL;
927         io.ntcreatex.in.fname = snamer1;
928         status = smb_raw_open(cli->tree, tctx, &io);
929         CHECK_STATUS(status, NT_STATUS_OK);
930         fnum1 = io.ntcreatex.out.file.fnum;
931
932         ret &= check_stream_list(tctx, cli, fname, 5, five1);
933
934         ZERO_STRUCT(sinfo);
935         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
936         sinfo.rename_information.in.file.fnum = fnum1;
937         sinfo.rename_information.in.overwrite = true;
938         sinfo.rename_information.in.root_fid = 0;
939         sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
940         status = smb_raw_setfileinfo(cli->tree, &sinfo);
941         CHECK_STATUS(status, NT_STATUS_OK);
942
943         ret &= check_stream_list(tctx, cli, fname, 5, five2);
944
945         ZERO_STRUCT(sinfo);
946         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
947         sinfo.rename_information.in.file.fnum = fnum1;
948         sinfo.rename_information.in.overwrite = false;
949         sinfo.rename_information.in.root_fid = 0;
950         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
951         status = smb_raw_setfileinfo(cli->tree, &sinfo);
952         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
953
954         ret &= check_stream_list(tctx, cli, fname, 5, five2);
955
956         ZERO_STRUCT(sinfo);
957         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
958         sinfo.rename_information.in.file.fnum = fnum1;
959         sinfo.rename_information.in.overwrite = true;
960         sinfo.rename_information.in.root_fid = 0;
961         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
962         status = smb_raw_setfileinfo(cli->tree, &sinfo);
963         if (torture_setting_bool(tctx, "samba4", false) ||
964             torture_setting_bool(tctx, "samba3", false)) {
965                 /* why should this rename be considered invalid?? */
966                 CHECK_STATUS(status, NT_STATUS_OK);
967                 ret &= check_stream_list(tctx, cli, fname, 4, four);
968         } else {
969                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
970                 ret &= check_stream_list(tctx, cli, fname, 5, five2);
971         }
972
973
974         /* TODO: we need to test more rename combinations */
975
976 done:
977         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
978         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
979         if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
980         status = smbcli_unlink(cli->tree, fname);
981         smbcli_deltree(cli->tree, BASEDIR);
982         return ret;
983 }
984
985 /*
986   test stream names
987 */
988 static bool test_stream_names2(struct torture_context *tctx,
989                                struct smbcli_state *cli)
990 {
991         NTSTATUS status;
992         union smb_open io;
993         const char *fname = BASEDIR "\\stream_names2.txt";
994         bool ret = true;
995         int fnum1 = -1;
996         uint8_t i;
997
998         if (!torture_setup_dir(cli, BASEDIR)) {
999                 return false;
1000         }
1001
1002         printf("(%s) testing stream names\n", __location__);
1003         io.generic.level = RAW_OPEN_NTCREATEX;
1004         io.ntcreatex.in.root_fid.fnum = 0;
1005         io.ntcreatex.in.flags = 0;
1006         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1007         io.ntcreatex.in.create_options = 0;
1008         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1009         io.ntcreatex.in.share_access = 0;
1010         io.ntcreatex.in.alloc_size = 0;
1011         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1012         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1013         io.ntcreatex.in.security_flags = 0;
1014         io.ntcreatex.in.fname = fname;
1015         status = smb_raw_open(cli->tree, tctx, &io);
1016         CHECK_STATUS(status, NT_STATUS_OK);
1017         fnum1 = io.ntcreatex.out.file.fnum;
1018
1019         for (i=0x01; i < 0x7F; i++) {
1020                 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1021                                              fname, i, i);
1022                 NTSTATUS expected;
1023
1024                 switch (i) {
1025                 case '/':/*0x2F*/
1026                 case ':':/*0x3A*/
1027                 case '\\':/*0x5C*/
1028                         expected = NT_STATUS_OBJECT_NAME_INVALID;
1029                         break;
1030                 default:
1031                         expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1032                         break;
1033                 }
1034
1035
1036                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1037                 io.ntcreatex.in.fname = path;
1038                 status = smb_raw_open(cli->tree, tctx, &io);
1039                 if (!NT_STATUS_EQUAL(status, expected)) {
1040                         printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1041                                 __location__, fname, isprint(i)?(char)i:' ', i,
1042                                 isprint(i)?"":" (not printable)",
1043                                 nt_errstr(expected));
1044                 }
1045                 CHECK_STATUS(status, expected);
1046
1047                 talloc_free(path);
1048         }
1049
1050 done:
1051         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1052         status = smbcli_unlink(cli->tree, fname);
1053         smbcli_deltree(cli->tree, BASEDIR);
1054         return ret;
1055 }
1056
1057 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1058         check_fnum = true; \
1059         call_name = #call; \
1060         sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1061         sfinfo.generic.in.file.fnum = fnum; \
1062         status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1063         if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1064                 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1065                         nt_errstr(status), nt_errstr(rightstatus)); \
1066                 ret = false; \
1067         } \
1068         finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1069         finfo1.generic.in.file.fnum = fnum; \
1070         status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1071         if (!NT_STATUS_IS_OK(status2)) { \
1072                 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1073                 ret = false; \
1074         }} while (0)
1075
1076 /*
1077   test stream renames
1078 */
1079 static bool test_stream_rename(struct torture_context *tctx,
1080                                    struct smbcli_state *cli)
1081 {
1082         NTSTATUS status, status2;
1083         union smb_open io;
1084         const char *fname = BASEDIR "\\stream_rename.txt";
1085         const char *sname1, *sname2;
1086         union smb_fileinfo finfo1;
1087         union smb_setfileinfo sfinfo;
1088         bool ret = true;
1089         int fnum = -1;
1090         bool check_fnum;
1091         const char *call_name;
1092
1093         if (!torture_setup_dir(cli, BASEDIR)) {
1094                 return false;
1095         }
1096
1097         sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1098         sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1099
1100         printf("(%s) testing stream renames\n", __location__);
1101         io.generic.level = RAW_OPEN_NTCREATEX;
1102         io.ntcreatex.in.root_fid.fnum = 0;
1103         io.ntcreatex.in.flags = 0;
1104         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1105                                       SEC_FILE_WRITE_ATTRIBUTE |
1106                                     SEC_RIGHTS_FILE_ALL;
1107         io.ntcreatex.in.create_options = 0;
1108         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1109         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1110         io.ntcreatex.in.alloc_size = 0;
1111         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1112         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1113         io.ntcreatex.in.security_flags = 0;
1114         io.ntcreatex.in.fname = sname1;
1115
1116         /* Create two streams. */
1117         status = smb_raw_open(cli->tree, tctx, &io);
1118         CHECK_STATUS(status, NT_STATUS_OK);
1119         fnum = io.ntcreatex.out.file.fnum;
1120         if (fnum != -1) smbcli_close(cli->tree, fnum);
1121
1122         io.ntcreatex.in.fname = sname2;
1123         status = smb_raw_open(cli->tree, tctx, &io);
1124         CHECK_STATUS(status, NT_STATUS_OK);
1125         fnum = io.ntcreatex.out.file.fnum;
1126
1127         if (fnum != -1) smbcli_close(cli->tree, fnum);
1128
1129         /*
1130          * Open the second stream.
1131          */
1132
1133         io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1134         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1135         status = smb_raw_open(cli->tree, tctx, &io);
1136         CHECK_STATUS(status, NT_STATUS_OK);
1137         fnum = io.ntcreatex.out.file.fnum;
1138
1139         /*
1140          * Now rename the second stream onto the first.
1141          */
1142
1143         ZERO_STRUCT(sfinfo);
1144
1145         sfinfo.rename_information.in.overwrite = 1;
1146         sfinfo.rename_information.in.root_fid  = 0;
1147         sfinfo.rename_information.in.new_name  = ":Stream One";
1148         CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1149
1150 done:
1151         if (fnum != -1) smbcli_close(cli->tree, fnum);
1152         status = smbcli_unlink(cli->tree, fname);
1153         smbcli_deltree(cli->tree, BASEDIR);
1154         return ret;
1155 }
1156
1157 static bool test_stream_rename2(struct torture_context *tctx,
1158                                struct smbcli_state *cli)
1159 {
1160         NTSTATUS status;
1161         union smb_open io;
1162         const char *fname1 = BASEDIR "\\stream.txt";
1163         const char *fname2 = BASEDIR "\\stream2.txt";
1164         const char *stream_name1 = ":Stream One:$DATA";
1165         const char *stream_name2 = ":Stream Two:$DATA";
1166         const char *stream_name_default = "::$DATA";
1167         const char *sname1;
1168         const char *sname2;
1169         bool ret = true;
1170         int fnum = -1;
1171         union smb_setfileinfo sinfo;
1172         union smb_rename rio;
1173
1174         if (!torture_setup_dir(cli, BASEDIR)) {
1175                 return false;
1176         }
1177
1178         sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1179         sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1180
1181         io.generic.level = RAW_OPEN_NTCREATEX;
1182         io.ntcreatex.in.root_fid.fnum = 0;
1183         io.ntcreatex.in.flags = 0;
1184         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1185             SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1186         io.ntcreatex.in.create_options = 0;
1187         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1188         io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1189                                         NTCREATEX_SHARE_ACCESS_WRITE |
1190                                         NTCREATEX_SHARE_ACCESS_DELETE);
1191         io.ntcreatex.in.alloc_size = 0;
1192         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1193         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1194         io.ntcreatex.in.security_flags = 0;
1195         io.ntcreatex.in.fname = sname1;
1196
1197         /* Open/create new stream. */
1198         status = smb_raw_open(cli->tree, tctx, &io);
1199         CHECK_STATUS(status, NT_STATUS_OK);
1200
1201         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1202
1203         /*
1204          * Check raw rename with <base>:<stream>.
1205          */
1206         printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1207                __location__);
1208         rio.generic.level = RAW_RENAME_NTRENAME;
1209         rio.ntrename.in.old_name = sname1;
1210         rio.ntrename.in.new_name = sname2;
1211         rio.ntrename.in.attrib = 0;
1212         rio.ntrename.in.cluster_size = 0;
1213         rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1214         status = smb_raw_rename(cli->tree, &rio);
1215         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1216
1217         /*
1218          * Check raw rename to the default stream using :<stream>.
1219          */
1220         printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1221                __location__);
1222         rio.ntrename.in.new_name = stream_name_default;
1223         status = smb_raw_rename(cli->tree, &rio);
1224         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1225
1226         /*
1227          * Check raw rename using :<stream>.
1228          */
1229         printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1230                __location__);
1231         rio.ntrename.in.new_name = stream_name2;
1232         status = smb_raw_rename(cli->tree, &rio);
1233         CHECK_STATUS(status, NT_STATUS_OK);
1234
1235         /*
1236          * Check raw rename of a stream to a file.
1237          */
1238         printf("(%s) Checking NTRENAME of a stream to a file\n",
1239                __location__);
1240         rio.ntrename.in.old_name = sname2;
1241         rio.ntrename.in.new_name = fname2;
1242         status = smb_raw_rename(cli->tree, &rio);
1243         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1244
1245         /*
1246          * Check raw rename of a file to a stream.
1247          */
1248         printf("(%s) Checking NTRENAME of a file to a stream\n",
1249                __location__);
1250
1251         /* Create the file. */
1252         io.ntcreatex.in.fname = fname2;
1253         status = smb_raw_open(cli->tree, tctx, &io);
1254         CHECK_STATUS(status, NT_STATUS_OK);
1255         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1256
1257         /* Try the rename. */
1258         rio.ntrename.in.old_name = fname2;
1259         rio.ntrename.in.new_name = sname1;
1260         status = smb_raw_rename(cli->tree, &rio);
1261         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1262
1263         /*
1264          * Reopen the stream for trans2 renames.
1265          */
1266         io.ntcreatex.in.fname = sname2;
1267         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1268         status = smb_raw_open(cli->tree, tctx, &io);
1269         CHECK_STATUS(status, NT_STATUS_OK);
1270         fnum = io.ntcreatex.out.file.fnum;
1271
1272         /*
1273          * Check trans2 rename of a stream using :<stream>.
1274          */
1275         printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1276                __location__);
1277         ZERO_STRUCT(sinfo);
1278         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1279         sinfo.rename_information.in.file.fnum = fnum;
1280         sinfo.rename_information.in.overwrite = 1;
1281         sinfo.rename_information.in.root_fid = 0;
1282         sinfo.rename_information.in.new_name = stream_name1;
1283         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1284         CHECK_STATUS(status, NT_STATUS_OK);
1285
1286         /*
1287          * Check trans2 rename of an overwriting stream using :<stream>.
1288          */
1289         printf("(%s) Checking trans2 rename of an overwriting stream using "
1290                ":<stream>\n", __location__);
1291
1292         /* Create second stream. */
1293         io.ntcreatex.in.fname = sname2;
1294         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1295         status = smb_raw_open(cli->tree, tctx, &io);
1296         CHECK_STATUS(status, NT_STATUS_OK);
1297         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1298
1299         /* Rename the first stream onto the second. */
1300         sinfo.rename_information.in.file.fnum = fnum;
1301         sinfo.rename_information.in.new_name = stream_name2;
1302         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1303         CHECK_STATUS(status, NT_STATUS_OK);
1304
1305         smbcli_close(cli->tree, fnum);
1306
1307         /*
1308          * Reopen the stream with the new name.
1309          */
1310         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1311         io.ntcreatex.in.fname = sname2;
1312         status = smb_raw_open(cli->tree, tctx, &io);
1313         CHECK_STATUS(status, NT_STATUS_OK);
1314         fnum = io.ntcreatex.out.file.fnum;
1315
1316         /*
1317          * Check trans2 rename of a stream using <base>:<stream>.
1318          */
1319         printf("(%s) Checking trans2 rename of a stream using "
1320                "<base>:<stream>\n", __location__);
1321         sinfo.rename_information.in.file.fnum = fnum;
1322         sinfo.rename_information.in.new_name = sname1;
1323         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1324         CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1325
1326         /*
1327          * Samba3 doesn't currently support renaming a stream to the default
1328          * stream.  This test does pass on windows.
1329          */
1330         if (torture_setting_bool(tctx, "samba3", false) ||
1331             torture_setting_bool(tctx, "samba4", false)) {
1332                 goto done;
1333         }
1334
1335         /*
1336          * Check trans2 rename to the default stream using :<stream>.
1337          */
1338         printf("(%s) Checking trans2 rename to defaualt stream using "
1339                ":<stream>\n", __location__);
1340         sinfo.rename_information.in.file.fnum = fnum;
1341         sinfo.rename_information.in.new_name = stream_name_default;
1342         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1343         CHECK_STATUS(status, NT_STATUS_OK);
1344
1345         smbcli_close(cli->tree, fnum);
1346
1347  done:
1348         smbcli_close(cli->tree, fnum);
1349         status = smbcli_unlink(cli->tree, fname1);
1350         status = smbcli_unlink(cli->tree, fname2);
1351         smbcli_deltree(cli->tree, BASEDIR);
1352         return ret;
1353 }
1354
1355 /*
1356   test stream renames
1357 */
1358 static bool test_stream_rename3(struct torture_context *tctx,
1359                                    struct smbcli_state *cli)
1360 {
1361         NTSTATUS status, status2;
1362         union smb_open io;
1363         const char *fname = BASEDIR "\\stream_rename.txt";
1364         const char *sname1, *sname2;
1365         union smb_fileinfo finfo1;
1366         union smb_setfileinfo sfinfo;
1367         bool ret = true;
1368         int fnum = -1;
1369         int fnum2 = -1;
1370         bool check_fnum;
1371         const char *call_name;
1372
1373         if (!torture_setup_dir(cli, BASEDIR)) {
1374                 return false;
1375         }
1376
1377         sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1378         sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1379
1380         printf("(%s) testing stream renames\n", __location__);
1381         io.generic.level = RAW_OPEN_NTCREATEX;
1382         io.ntcreatex.in.root_fid.fnum = 0;
1383         io.ntcreatex.in.flags = 0;
1384         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1385                                       SEC_FILE_WRITE_ATTRIBUTE |
1386                                     SEC_RIGHTS_FILE_ALL;
1387         io.ntcreatex.in.create_options = 0;
1388         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1389         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1390             NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1391         io.ntcreatex.in.alloc_size = 0;
1392         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1393         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1394         io.ntcreatex.in.security_flags = 0;
1395         io.ntcreatex.in.fname = sname1;
1396
1397         /* Create two streams. */
1398         status = smb_raw_open(cli->tree, tctx, &io);
1399         CHECK_STATUS(status, NT_STATUS_OK);
1400         fnum = io.ntcreatex.out.file.fnum;
1401         if (fnum != -1) smbcli_close(cli->tree, fnum);
1402
1403         io.ntcreatex.in.fname = sname2;
1404         status = smb_raw_open(cli->tree, tctx, &io);
1405         CHECK_STATUS(status, NT_STATUS_OK);
1406         fnum = io.ntcreatex.out.file.fnum;
1407
1408         if (fnum != -1) smbcli_close(cli->tree, fnum);
1409
1410         /* open the second stream. */
1411         io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1412         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1413         status = smb_raw_open(cli->tree, tctx, &io);
1414         CHECK_STATUS(status, NT_STATUS_OK);
1415         fnum = io.ntcreatex.out.file.fnum;
1416
1417         /* Keep a handle to the first stream open. */
1418         io.ntcreatex.in.fname = sname1;
1419         io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1420         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1421         status = smb_raw_open(cli->tree, tctx, &io);
1422         CHECK_STATUS(status, NT_STATUS_OK);
1423         fnum2 = io.ntcreatex.out.file.fnum;
1424
1425         ZERO_STRUCT(sfinfo);
1426         sfinfo.rename_information.in.overwrite = 1;
1427         sfinfo.rename_information.in.root_fid  = 0;
1428         sfinfo.rename_information.in.new_name  = ":MStream Two:$DATA";
1429         if (torture_setting_bool(tctx, "samba4", false) ||
1430             torture_setting_bool(tctx, "samba3", false)) {
1431                 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1432         } else {
1433                 CHECK_CALL_FNUM(RENAME_INFORMATION,
1434                     NT_STATUS_INVALID_PARAMETER);
1435         }
1436
1437
1438 done:
1439         if (fnum != -1) smbcli_close(cli->tree, fnum);
1440         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1441         status = smbcli_unlink(cli->tree, fname);
1442         smbcli_deltree(cli->tree, BASEDIR);
1443         return ret;
1444 }
1445
1446 static bool create_file_with_stream(struct torture_context *tctx,
1447                                     struct smbcli_state *cli,
1448                                     const char *stream)
1449 {
1450         NTSTATUS status;
1451         bool ret = true;
1452         union smb_open io;
1453
1454         /* Create a file with a stream */
1455         io.generic.level = RAW_OPEN_NTCREATEX;
1456         io.ntcreatex.in.root_fid.fnum = 0;
1457         io.ntcreatex.in.flags = 0;
1458         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1459             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1460         io.ntcreatex.in.create_options = 0;
1461         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1462         io.ntcreatex.in.share_access = 0;
1463         io.ntcreatex.in.alloc_size = 0;
1464         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1465         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1466         io.ntcreatex.in.security_flags = 0;
1467         io.ntcreatex.in.fname = stream;
1468
1469         status = smb_raw_open(cli->tree, tctx, &io);
1470         CHECK_STATUS(status, NT_STATUS_OK);
1471
1472  done:
1473         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1474         return ret;
1475 }
1476
1477 /* Test how streams interact with create dispositions */
1478 static bool test_stream_create_disposition(struct torture_context *tctx,
1479                                            struct smbcli_state *cli)
1480 {
1481         NTSTATUS status;
1482         union smb_open io;
1483         const char *fname = BASEDIR "\\stream.txt";
1484         const char *stream = "Stream One:$DATA";
1485         const char *fname_stream;
1486         const char *default_stream_name = "::$DATA";
1487         const char *stream_list[2];
1488         bool ret = false;
1489         int fnum = -1;
1490
1491         if (!torture_setup_dir(cli, BASEDIR)) {
1492                 return false;
1493         }
1494
1495         fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1496
1497         stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1498         stream_list[1] = default_stream_name;
1499
1500         if (!create_file_with_stream(tctx, cli, fname_stream)) {
1501                 goto done;
1502         }
1503
1504         /* Open the base file with OPEN */
1505         io.generic.level = RAW_OPEN_NTCREATEX;
1506         io.ntcreatex.in.root_fid.fnum = 0;
1507         io.ntcreatex.in.flags = 0;
1508         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1509             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1510         io.ntcreatex.in.create_options = 0;
1511         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1512         io.ntcreatex.in.share_access = 0;
1513         io.ntcreatex.in.alloc_size = 0;
1514         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1515         io.ntcreatex.in.security_flags = 0;
1516         io.ntcreatex.in.fname = fname;
1517
1518         /*
1519          * check ntcreatex open: sanity check
1520          */
1521         printf("(%s) Checking ntcreatex disp: open\n", __location__);
1522         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1523         status = smb_raw_open(cli->tree, tctx, &io);
1524         CHECK_STATUS(status, NT_STATUS_OK);
1525         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1526         if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1527                 goto done;
1528         }
1529
1530         /*
1531          * check ntcreatex overwrite
1532          */
1533         printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1534         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1535         status = smb_raw_open(cli->tree, tctx, &io);
1536         CHECK_STATUS(status, NT_STATUS_OK);
1537         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1538         if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1539                 goto done;
1540         }
1541
1542         /*
1543          * check ntcreatex overwrite_if
1544          */
1545         printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1546         smbcli_unlink(cli->tree, fname);
1547         if (!create_file_with_stream(tctx, cli, fname_stream)) {
1548                 goto done;
1549         }
1550
1551         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1552         status = smb_raw_open(cli->tree, tctx, &io);
1553         CHECK_STATUS(status, NT_STATUS_OK);
1554         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1555         if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1556                 goto done;
1557         }
1558
1559         /*
1560          * check ntcreatex supersede
1561          */
1562         printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1563         smbcli_unlink(cli->tree, fname);
1564         if (!create_file_with_stream(tctx, cli, fname_stream)) {
1565                 goto done;
1566         }
1567
1568         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1569         status = smb_raw_open(cli->tree, tctx, &io);
1570         CHECK_STATUS(status, NT_STATUS_OK);
1571         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1572         if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1573                 goto done;
1574         }
1575
1576         /*
1577          * check ntcreatex overwrite_if on a stream.
1578          */
1579         printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1580                __location__);
1581         smbcli_unlink(cli->tree, fname);
1582         if (!create_file_with_stream(tctx, cli, fname_stream)) {
1583                 goto done;
1584         }
1585
1586         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1587         io.ntcreatex.in.fname = fname_stream;
1588         status = smb_raw_open(cli->tree, tctx, &io);
1589         CHECK_STATUS(status, NT_STATUS_OK);
1590         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1591         if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1592                 goto done;
1593         }
1594
1595         /*
1596          * check openx overwrite_if
1597          */
1598         printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1599         smbcli_unlink(cli->tree, fname);
1600         if (!create_file_with_stream(tctx, cli, fname_stream)) {
1601                 goto done;
1602         }
1603
1604         io.openx.level = RAW_OPEN_OPENX;
1605         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1606         io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1607         io.openx.in.search_attrs = 0;
1608         io.openx.in.file_attrs = 0;
1609         io.openx.in.write_time = 0;
1610         io.openx.in.size = 1024*1024;
1611         io.openx.in.timeout = 0;
1612         io.openx.in.fname = fname;
1613
1614         io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1615         status = smb_raw_open(cli->tree, tctx, &io);
1616         CHECK_STATUS(status, NT_STATUS_OK);
1617         smbcli_close(cli->tree, io.openx.out.file.fnum);
1618         if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1619                 goto done;
1620         }
1621
1622         ret = true;
1623
1624  done:
1625         smbcli_close(cli->tree, fnum);
1626         smbcli_unlink(cli->tree, fname);
1627         smbcli_deltree(cli->tree, BASEDIR);
1628         return ret;
1629 }
1630
1631 /* Test streaminfo with enough streams on a file to fill up the buffer.  */
1632 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1633                                          struct smbcli_state *cli)
1634 {
1635 #define LONG_STREAM_SIZE 2
1636         char *lstream_name;
1637         const char *fname = BASEDIR "\\stream.txt";
1638         const char *fname_stream;
1639         NTSTATUS status;
1640         bool ret = true;
1641         int i;
1642         union smb_fileinfo finfo;
1643
1644         if (!torture_setup_dir(cli, BASEDIR)) {
1645                 return false;
1646         }
1647
1648         lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1649
1650         for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1651                 lstream_name[i] = (char)('a' + i%26);
1652         }
1653         lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1654
1655         torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1656         for (i = 0; i < 10000; i++) {
1657                 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1658                                                lstream_name, i);
1659                 ret = create_file_with_stream(tctx, cli, fname_stream);
1660                 if (!ret) {
1661                         goto done;
1662                 }
1663         }
1664
1665         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1666         finfo.generic.in.file.path = fname;
1667
1668         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1669         CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1670
1671  done:
1672         smbcli_unlink(cli->tree, fname);
1673         smbcli_deltree(cli->tree, BASEDIR);
1674         return ret;
1675 }
1676
1677 /* Test the effect of setting attributes on a stream. */
1678 static bool test_stream_attributes(struct torture_context *tctx,
1679                                          struct smbcli_state *cli)
1680 {
1681         bool ret = true;
1682         NTSTATUS status;
1683         union smb_open io;
1684         const char *fname = BASEDIR "\\stream_attr.txt";
1685         const char *stream = "Stream One:$DATA";
1686         const char *fname_stream;
1687         int fnum = -1;
1688         union smb_fileinfo finfo;
1689         union smb_setfileinfo sfinfo;
1690         time_t basetime = (time(NULL) - 86400) & ~1;
1691
1692         if (!torture_setup_dir(cli, BASEDIR)) {
1693                 return false;
1694         }
1695
1696         torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1697
1698         fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1699
1700         /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1701         ret = create_file_with_stream(tctx, cli, fname_stream);
1702         if (!ret) {
1703                 goto done;
1704         }
1705
1706         ZERO_STRUCT(finfo);
1707         finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1708         finfo.generic.in.file.path = fname;
1709         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1710         CHECK_STATUS(status, NT_STATUS_OK);
1711
1712         if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1713                 printf("(%s) Incorrect attrib %x - should be %x\n", \
1714                        __location__, (unsigned int)finfo.basic_info.out.attrib,
1715                         (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1716                 ret = false;
1717                 goto done;
1718         }
1719
1720         /* Now open the stream name. */
1721
1722         io.generic.level = RAW_OPEN_NTCREATEX;
1723         io.ntcreatex.in.root_fid.fnum = 0;
1724         io.ntcreatex.in.flags = 0;
1725         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1726             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1727         io.ntcreatex.in.create_options = 0;
1728         io.ntcreatex.in.file_attr = 0;
1729         io.ntcreatex.in.share_access = 0;
1730         io.ntcreatex.in.alloc_size = 0;
1731         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1732         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1733         io.ntcreatex.in.security_flags = 0;
1734         io.ntcreatex.in.fname = fname_stream;
1735
1736         status = smb_raw_open(cli->tree, tctx, &io);
1737         CHECK_STATUS(status, NT_STATUS_OK);
1738
1739         fnum = io.ntcreatex.out.file.fnum;
1740
1741         /* Change the attributes + time on the stream fnum. */
1742         ZERO_STRUCT(sfinfo);
1743         sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1744         unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1745
1746         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1747         sfinfo.generic.in.file.fnum = fnum;
1748         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1749         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { 
1750                 printf("(%s) %s - %s (should be %s)\n", __location__, "SETATTR", 
1751                         nt_errstr(status), nt_errstr(NT_STATUS_OK));
1752                 ret = false;
1753                 goto done;
1754         }
1755
1756         smbcli_close(cli->tree, fnum);
1757         fnum = -1;
1758
1759         ZERO_STRUCT(finfo);
1760         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1761         finfo.generic.in.file.path = fname;
1762         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1763         if (!NT_STATUS_IS_OK(status)) {
1764                 printf("(%s) %s pathinfo - %s\n", __location__, "SETATTRE", nt_errstr(status));
1765                 ret = false;
1766                 goto done;
1767         }
1768
1769         if (finfo.all_info.out.attrib != FILE_ATTRIBUTE_READONLY) {
1770                 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1771                         __location__,
1772                         (unsigned int)finfo.all_info.out.attrib,
1773                         (unsigned int)FILE_ATTRIBUTE_READONLY);
1774                 ret = false;
1775                 goto done;
1776         }
1777
1778         if (nt_time_to_unix(finfo.all_info.out.write_time) != basetime) {
1779                 printf("(%s) time incorrect.\n",
1780                         __location__);
1781                 ret = false;
1782                 goto done;
1783         }
1784
1785  done:
1786
1787         if (fnum != -1) {
1788                 smbcli_close(cli->tree, fnum);
1789         }
1790         smbcli_unlink(cli->tree, fname);
1791         smbcli_deltree(cli->tree, BASEDIR);
1792         return ret;
1793 }
1794
1795 /**
1796  * A rough approximation of how a windows client creates the streams for use
1797  * in the summary tab.
1798  */
1799 static bool test_stream_summary_tab(struct torture_context *tctx,
1800                                     struct smbcli_state *cli)
1801 {
1802         bool ret = true;
1803         NTSTATUS status;
1804         union smb_open io;
1805         const char *fname = BASEDIR "\\stream_summary.txt";
1806         const char *stream = ":\005SummaryInformation:$DATA";
1807         const char *fname_stream = NULL;
1808         const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1809         const char *fname_tmp_stream = NULL;
1810         int fnum = -1;
1811         union smb_fileinfo finfo;
1812         union smb_rename rio;
1813         ssize_t retsize;
1814
1815         if (!torture_setup_dir(cli, BASEDIR)) {
1816                 return false;
1817         }
1818
1819         fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1820         fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1821                                            tmp_stream);
1822
1823         /* Create summary info stream */
1824         ret = create_file_with_stream(tctx, cli, fname_stream);
1825         if (!ret) {
1826                 goto done;
1827         }
1828
1829         /* Create summary info tmp update stream */
1830         ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1831         if (!ret) {
1832                 goto done;
1833         }
1834
1835         /* Open tmp stream and write to it */
1836         io.generic.level = RAW_OPEN_NTCREATEX;
1837         io.ntcreatex.in.root_fid.fnum = 0;
1838         io.ntcreatex.in.flags = 0;
1839         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1840         io.ntcreatex.in.create_options = 0;
1841         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1842         io.ntcreatex.in.share_access = 0;
1843         io.ntcreatex.in.alloc_size = 0;
1844         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1845         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1846         io.ntcreatex.in.security_flags = 0;
1847         io.ntcreatex.in.fname = fname_tmp_stream;
1848
1849         status = smb_raw_open(cli->tree, tctx, &io);
1850         CHECK_STATUS(status, NT_STATUS_OK);
1851         fnum = io.ntcreatex.out.file.fnum;
1852
1853         retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1854         CHECK_VALUE(retsize, 9);
1855
1856         /* close the tmp stream. */
1857         smbcli_close(cli->tree, fnum);
1858         fnum = -1;
1859
1860         /* Delete the current stream */
1861         smbcli_unlink(cli->tree, fname_stream);
1862
1863         /* Do the rename. */
1864         rio.generic.level = RAW_RENAME_RENAME;
1865         rio.rename.in.pattern1 = fname_tmp_stream;
1866         rio.rename.in.pattern2 = stream;
1867         rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1868             FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1869         status = smb_raw_rename(cli->tree, &rio);
1870         CHECK_STATUS(status, NT_STATUS_OK);
1871
1872         /* Try to open the tmp stream that we just renamed away. */
1873         status = smb_raw_open(cli->tree, tctx, &io);
1874         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1875
1876         /* Query the base file to make sure it's still there.  */
1877         finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1878         finfo.generic.in.file.path = fname;
1879
1880         status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1881         CHECK_STATUS(status, NT_STATUS_OK);
1882
1883  done:
1884
1885         if (fnum != -1) {
1886                 smbcli_close(cli->tree, fnum);
1887         }
1888         smbcli_unlink(cli->tree, fname);
1889
1890         smbcli_deltree(cli->tree, BASEDIR);
1891         return ret;
1892 }
1893
1894 /* 
1895    basic testing of streams calls
1896 */
1897 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
1898 {
1899         struct torture_suite *suite = torture_suite_create(tctx, "streams");
1900
1901         torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
1902         torture_suite_add_1smb_test(suite, "io", test_stream_io);
1903         torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
1904         torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
1905         torture_suite_add_1smb_test(suite, "names", test_stream_names);
1906         torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
1907         torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
1908         torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
1909         torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
1910         torture_suite_add_1smb_test(suite, "createdisp",
1911             test_stream_create_disposition);
1912         torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
1913         torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
1914
1915         /* torture_suite_add_1smb_test(suite, "LARGESTREAMINFO", */
1916         /*     test_stream_large_streaminfo); */
1917
1918         return suite;
1919 }