And the prize for the most pain caused in the build farm for a simple
[ira/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         smbcli_unlink(cli->tree, fname);
644         return ret;
645 }
646
647 /*
648   test stream names
649 */
650 static bool test_stream_names(struct torture_context *tctx,
651                               struct smbcli_state *cli,
652                               TALLOC_CTX *mem_ctx)
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         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
690         sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
691         sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
692         sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
693         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
694         snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
695         snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
696         snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "BeforeRename");
697         snamer2 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "AfterRename");
698
699         printf("(%s) testing stream names\n", __location__);
700         io.generic.level = RAW_OPEN_NTCREATEX;
701         io.ntcreatex.in.root_fid = 0;
702         io.ntcreatex.in.flags = 0;
703         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
704         io.ntcreatex.in.create_options = 0;
705         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
706         io.ntcreatex.in.share_access = 0;
707         io.ntcreatex.in.alloc_size = 0;
708         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
709         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
710         io.ntcreatex.in.security_flags = 0;
711         io.ntcreatex.in.fname = sname1;
712
713         status = smb_raw_open(cli->tree, mem_ctx, &io);
714         CHECK_STATUS(status, NT_STATUS_OK);
715         fnum1 = io.ntcreatex.out.file.fnum;
716
717         /*
718          * A different stream does not give a sharing violation
719          */
720
721         io.ntcreatex.in.fname = sname2;
722         status = smb_raw_open(cli->tree, mem_ctx, &io);
723         CHECK_STATUS(status, NT_STATUS_OK);
724         fnum2 = io.ntcreatex.out.file.fnum;
725
726         /*
727          * ... whereas the same stream does with unchanged access/share_access
728          * flags
729          */
730
731         io.ntcreatex.in.fname = sname1;
732         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
733         status = smb_raw_open(cli->tree, mem_ctx, &io);
734         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
735
736         io.ntcreatex.in.fname = sname1b;
737         status = smb_raw_open(cli->tree, mem_ctx, &io);
738         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
739
740         io.ntcreatex.in.fname = sname1c;
741         status = smb_raw_open(cli->tree, mem_ctx, &io);
742         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
743                 /* w2k returns INVALID_PARAMETER */
744                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
745         } else {
746                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
747         }
748
749         io.ntcreatex.in.fname = sname1d;
750         status = smb_raw_open(cli->tree, mem_ctx, &io);
751         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
752                 /* w2k returns INVALID_PARAMETER */
753                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
754         } else {
755                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
756         }
757
758         io.ntcreatex.in.fname = sname2;
759         status = smb_raw_open(cli->tree, mem_ctx, &io);
760         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
761
762         io.ntcreatex.in.fname = snamew;
763         status = smb_raw_open(cli->tree, mem_ctx, &io);
764         CHECK_STATUS(status, NT_STATUS_OK);
765         fnum3 = io.ntcreatex.out.file.fnum;
766
767         io.ntcreatex.in.fname = snamew2;
768         status = smb_raw_open(cli->tree, mem_ctx, &io);
769         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
770
771         ret &= check_stream_list(cli, fname, 4, four);
772
773         smbcli_close(cli->tree, fnum1);
774         smbcli_close(cli->tree, fnum2);
775         smbcli_close(cli->tree, fnum3);
776
777         if (torture_setting_bool(tctx, "samba4", true)) {
778                 goto done;
779         }
780
781         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
782         finfo.generic.in.file.path = fname;
783         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
784         CHECK_STATUS(status, NT_STATUS_OK);
785
786         ret &= check_stream_list(cli, fname, 4, four);
787
788         for (i=0; i < 4; i++) {
789                 NTTIME write_time;
790                 uint64_t stream_size;
791                 char *path = talloc_asprintf(tctx, "%s%s",
792                                              fname, four[i]);
793
794                 char *rpath = talloc_strdup(path, path);
795                 char *p = strrchr(rpath, ':');
796                 /* eat :$DATA */
797                 *p = 0;
798                 p--;
799                 if (*p == ':') {
800                         /* eat ::$DATA */
801                         *p = 0;
802                 }
803                 printf("(%s): i[%u][%s]\n", __location__, i, path);
804                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
805                 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
806                                               SEC_FILE_WRITE_ATTRIBUTE |
807                                             SEC_RIGHTS_FILE_ALL;
808                 io.ntcreatex.in.fname = path;
809                 status = smb_raw_open(cli->tree, mem_ctx, &io);
810                 CHECK_STATUS(status, NT_STATUS_OK);
811                 fnum1 = io.ntcreatex.out.file.fnum;
812
813                 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
814                 finfo.generic.in.file.path = fname;
815                 status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
816                 CHECK_STATUS(status, NT_STATUS_OK);
817
818                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
819                 stinfo.generic.in.file.fnum = fnum1;
820                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
821                 CHECK_STATUS(status, NT_STATUS_OK);
822                 if (!torture_setting_bool(tctx, "samba3", false)) {
823                         CHECK_NTTIME(stinfo.all_info.out.create_time,
824                                      finfo.all_info.out.create_time);
825                         CHECK_NTTIME(stinfo.all_info.out.access_time,
826                                      finfo.all_info.out.access_time);
827                         CHECK_NTTIME(stinfo.all_info.out.write_time,
828                                      finfo.all_info.out.write_time);
829                         CHECK_NTTIME(stinfo.all_info.out.change_time,
830                                      finfo.all_info.out.change_time);
831                 }
832                 CHECK_VALUE(stinfo.all_info.out.attrib,
833                             finfo.all_info.out.attrib);
834                 CHECK_VALUE(stinfo.all_info.out.size,
835                             finfo.all_info.out.size);
836                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
837                             finfo.all_info.out.delete_pending);
838                 CHECK_VALUE(stinfo.all_info.out.directory,
839                             finfo.all_info.out.directory);
840                 CHECK_VALUE(stinfo.all_info.out.ea_size,
841                             finfo.all_info.out.ea_size);
842
843                 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
844                 stinfo.generic.in.file.fnum = fnum1;
845                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
846                 CHECK_STATUS(status, NT_STATUS_OK);
847                 if (!torture_setting_bool(tctx, "samba3", false)) {
848                         CHECK_STR(rpath, stinfo.name_info.out.fname.s);
849                 }
850
851                 write_time = finfo.all_info.out.write_time;
852                 write_time += i*1000000;
853                 write_time /= 1000000;
854                 write_time *= 1000000;
855
856                 ZERO_STRUCT(sinfo);
857                 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
858                 sinfo.basic_info.in.file.fnum = fnum1;
859                 sinfo.basic_info.in.write_time = write_time;
860                 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
861                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
862                 CHECK_STATUS(status, NT_STATUS_OK);
863
864                 stream_size = i*8192;
865
866                 ZERO_STRUCT(sinfo);
867                 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
868                 sinfo.end_of_file_info.in.file.fnum = fnum1;
869                 sinfo.end_of_file_info.in.size = stream_size;
870                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
871                 CHECK_STATUS(status, NT_STATUS_OK);
872
873                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
874                 stinfo.generic.in.file.fnum = fnum1;
875                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
876                 CHECK_STATUS(status, NT_STATUS_OK);
877                 if (!torture_setting_bool(tctx, "samba3", false)) {
878                         CHECK_NTTIME(stinfo.all_info.out.write_time,
879                                      write_time);
880                         CHECK_VALUE(stinfo.all_info.out.attrib,
881                                     finfo.all_info.out.attrib);
882                 }
883                 CHECK_VALUE(stinfo.all_info.out.size,
884                             stream_size);
885                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
886                             finfo.all_info.out.delete_pending);
887                 CHECK_VALUE(stinfo.all_info.out.directory,
888                             finfo.all_info.out.directory);
889                 CHECK_VALUE(stinfo.all_info.out.ea_size,
890                             finfo.all_info.out.ea_size);
891
892                 ret &= check_stream_list(cli, fname, 4, four);
893
894                 smbcli_close(cli->tree, fnum1);
895                 talloc_free(path);
896         }
897
898         printf("(%s): testing stream renames\n", __location__);
899         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
900         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
901                                       SEC_FILE_WRITE_ATTRIBUTE |
902                                     SEC_RIGHTS_FILE_ALL;
903         io.ntcreatex.in.fname = snamer1;
904         status = smb_raw_open(cli->tree, mem_ctx, &io);
905         CHECK_STATUS(status, NT_STATUS_OK);
906         fnum1 = io.ntcreatex.out.file.fnum;
907
908         ret &= check_stream_list(cli, fname, 5, five1);
909
910         ZERO_STRUCT(sinfo);
911         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
912         sinfo.rename_information.in.file.fnum = fnum1;
913         sinfo.rename_information.in.overwrite = true;
914         sinfo.rename_information.in.root_fid = 0;
915         sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
916         status = smb_raw_setfileinfo(cli->tree, &sinfo);
917         CHECK_STATUS(status, NT_STATUS_OK);
918
919         ret &= check_stream_list(cli, fname, 5, five2);
920
921         ZERO_STRUCT(sinfo);
922         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
923         sinfo.rename_information.in.file.fnum = fnum1;
924         sinfo.rename_information.in.overwrite = false;
925         sinfo.rename_information.in.root_fid = 0;
926         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
927         status = smb_raw_setfileinfo(cli->tree, &sinfo);
928         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
929
930         ret &= check_stream_list(cli, fname, 5, five2);
931
932         ZERO_STRUCT(sinfo);
933         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
934         sinfo.rename_information.in.file.fnum = fnum1;
935         sinfo.rename_information.in.overwrite = true;
936         sinfo.rename_information.in.root_fid = 0;
937         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
938         status = smb_raw_setfileinfo(cli->tree, &sinfo);
939         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
940
941         ret &= check_stream_list(cli, fname, 5, five2);
942
943         /* TODO: we need to test more rename combinations */
944
945 done:
946         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
947         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
948         if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
949         status = smbcli_unlink(cli->tree, fname);
950         return ret;
951 }
952
953 /*
954   test stream names
955 */
956 static bool test_stream_names2(struct torture_context *tctx,
957                                struct smbcli_state *cli,
958                                TALLOC_CTX *mem_ctx)
959 {
960         NTSTATUS status;
961         union smb_open io;
962         const char *fname = BASEDIR "\\stream_names2.txt";
963         bool ret = true;
964         int fnum1 = -1;
965         uint8_t i;
966
967         printf("(%s) testing stream names\n", __location__);
968         io.generic.level = RAW_OPEN_NTCREATEX;
969         io.ntcreatex.in.root_fid = 0;
970         io.ntcreatex.in.flags = 0;
971         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
972         io.ntcreatex.in.create_options = 0;
973         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
974         io.ntcreatex.in.share_access = 0;
975         io.ntcreatex.in.alloc_size = 0;
976         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
977         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
978         io.ntcreatex.in.security_flags = 0;
979         io.ntcreatex.in.fname = fname;
980         status = smb_raw_open(cli->tree, mem_ctx, &io);
981         CHECK_STATUS(status, NT_STATUS_OK);
982         fnum1 = io.ntcreatex.out.file.fnum;
983
984         for (i=0x01; i < 0x7F; i++) {
985                 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
986                                              fname, i, i);
987                 NTSTATUS expected;
988
989                 switch (i) {
990                 case '/':/*0x2F*/
991                 case ':':/*0x3A*/
992                 case '\\':/*0x5C*/
993                         expected = NT_STATUS_OBJECT_NAME_INVALID;
994                         break;
995                 default:
996                         expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
997                         break;
998                 }
999
1000
1001                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1002                 io.ntcreatex.in.fname = path;
1003                 status = smb_raw_open(cli->tree, mem_ctx, &io);
1004                 if (!NT_STATUS_EQUAL(status, expected)) {
1005                         printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1006                                 __location__, fname, isprint(i)?(char)i:' ', i,
1007                                 isprint(i)?"":" (not printable)",
1008                                 nt_errstr(expected));
1009                 }
1010                 CHECK_STATUS(status, expected);
1011
1012                 talloc_free(path);
1013         }
1014
1015 done:
1016         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1017         status = smbcli_unlink(cli->tree, fname);
1018         return ret;
1019 }
1020
1021 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1022         check_fnum = true; \
1023         call_name = #call; \
1024         sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1025         sfinfo.generic.in.file.fnum = fnum; \
1026         status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1027         if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1028                 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1029                         nt_errstr(status), nt_errstr(rightstatus)); \
1030                 ret = false; \
1031         } \
1032         finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1033         finfo1.generic.in.file.fnum = fnum; \
1034         status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1035         if (!NT_STATUS_IS_OK(status2)) { \
1036                 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1037                 ret = false; \
1038         }} while (0)
1039
1040 /*
1041   test stream renames
1042 */
1043 static bool test_stream_rename(struct torture_context *tctx,
1044                                    struct smbcli_state *cli,
1045                                    TALLOC_CTX *mem_ctx)
1046 {
1047         NTSTATUS status, status2;
1048         union smb_open io;
1049         const char *fname = BASEDIR "\\stream_rename.txt";
1050         const char *sname1, *sname2;
1051         union smb_fileinfo finfo1;
1052         union smb_setfileinfo sfinfo;
1053         bool ret = true;
1054         int fnum = -1;
1055         bool check_fnum;
1056         const char *call_name;
1057
1058         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
1059         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
1060
1061         printf("(%s) testing stream renames\n", __location__);
1062         io.generic.level = RAW_OPEN_NTCREATEX;
1063         io.ntcreatex.in.root_fid = 0;
1064         io.ntcreatex.in.flags = 0;
1065         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1066                                       SEC_FILE_WRITE_ATTRIBUTE |
1067                                     SEC_RIGHTS_FILE_ALL;
1068         io.ntcreatex.in.create_options = 0;
1069         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1070         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1071         io.ntcreatex.in.alloc_size = 0;
1072         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1073         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1074         io.ntcreatex.in.security_flags = 0;
1075         io.ntcreatex.in.fname = sname1;
1076
1077         /* Create two streams. */
1078         status = smb_raw_open(cli->tree, mem_ctx, &io);
1079         CHECK_STATUS(status, NT_STATUS_OK);
1080         fnum = io.ntcreatex.out.file.fnum;
1081         if (fnum != -1) smbcli_close(cli->tree, fnum);
1082
1083         io.ntcreatex.in.fname = sname2;
1084         status = smb_raw_open(cli->tree, mem_ctx, &io);
1085         CHECK_STATUS(status, NT_STATUS_OK);
1086         fnum = io.ntcreatex.out.file.fnum;
1087
1088         if (fnum != -1) smbcli_close(cli->tree, fnum);
1089
1090         /*
1091          * Open the second stream.
1092          */
1093
1094         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1095         status = smb_raw_open(cli->tree, mem_ctx, &io);
1096         CHECK_STATUS(status, NT_STATUS_OK);
1097         fnum = io.ntcreatex.out.file.fnum;
1098
1099         /*
1100          * Now rename the second stream onto the first.
1101          */
1102
1103         ZERO_STRUCT(sfinfo);
1104
1105         sfinfo.rename_information.in.overwrite = 1;
1106         sfinfo.rename_information.in.root_fid  = 0;
1107         sfinfo.rename_information.in.new_name  = ":Stream One";
1108         CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1109
1110 done:
1111         if (fnum != -1) smbcli_close(cli->tree, fnum);
1112         status = smbcli_unlink(cli->tree, fname);
1113         return ret;
1114 }
1115
1116 static bool test_stream_rename2(struct torture_context *tctx,
1117                                struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1118 {
1119         NTSTATUS status;
1120         union smb_open io;
1121         const char *fname1 = BASEDIR "\\stream.txt";
1122         const char *fname2 = BASEDIR "\\stream2.txt";
1123         const char *stream_name1 = ":Stream One:$DATA";
1124         const char *stream_name2 = ":Stream Two:$DATA";
1125         const char *stream_name_default = "::$DATA";
1126         const char *sname1;
1127         const char *sname2;
1128         bool ret = true;
1129         int fnum = -1;
1130         union smb_setfileinfo sinfo;
1131         union smb_rename rio;
1132
1133         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
1134         sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
1135
1136         io.generic.level = RAW_OPEN_NTCREATEX;
1137         io.ntcreatex.in.root_fid = 0;
1138         io.ntcreatex.in.flags = 0;
1139         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1140             SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1141         io.ntcreatex.in.create_options = 0;
1142         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1143         io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1144                                         NTCREATEX_SHARE_ACCESS_WRITE |
1145                                         NTCREATEX_SHARE_ACCESS_DELETE);
1146         io.ntcreatex.in.alloc_size = 0;
1147         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1148         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1149         io.ntcreatex.in.security_flags = 0;
1150         io.ntcreatex.in.fname = sname1;
1151
1152         /* Open/create new stream. */
1153         status = smb_raw_open(cli->tree, mem_ctx, &io);
1154         CHECK_STATUS(status, NT_STATUS_OK);
1155
1156         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1157
1158         /*
1159          * Check raw rename with <base>:<stream>.
1160          */
1161         printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1162                __location__);
1163         rio.generic.level = RAW_RENAME_NTRENAME;
1164         rio.ntrename.in.old_name = sname1;
1165         rio.ntrename.in.new_name = sname2;
1166         rio.ntrename.in.attrib = 0;
1167         rio.ntrename.in.cluster_size = 0;
1168         rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1169         status = smb_raw_rename(cli->tree, &rio);
1170         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1171
1172         /*
1173          * Check raw rename to the default stream using :<stream>.
1174          */
1175         printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1176                __location__);
1177         rio.ntrename.in.new_name = stream_name_default;
1178         status = smb_raw_rename(cli->tree, &rio);
1179         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1180
1181         /*
1182          * Check raw rename using :<stream>.
1183          */
1184         printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1185                __location__);
1186         rio.ntrename.in.new_name = stream_name2;
1187         status = smb_raw_rename(cli->tree, &rio);
1188         CHECK_STATUS(status, NT_STATUS_OK);
1189
1190         /*
1191          * Check raw rename of a stream to a file.
1192          */
1193         printf("(%s) Checking NTRENAME of a stream to a file\n",
1194                __location__);
1195         rio.ntrename.in.old_name = sname2;
1196         rio.ntrename.in.new_name = fname2;
1197         status = smb_raw_rename(cli->tree, &rio);
1198         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1199
1200         /*
1201          * Check raw rename of a file to a stream.
1202          */
1203         printf("(%s) Checking NTRENAME of a file to a stream\n",
1204                __location__);
1205
1206         /* Create the file. */
1207         io.ntcreatex.in.fname = fname2;
1208         status = smb_raw_open(cli->tree, mem_ctx, &io);
1209         CHECK_STATUS(status, NT_STATUS_OK);
1210         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1211
1212         /* Try the rename. */
1213         rio.ntrename.in.old_name = fname2;
1214         rio.ntrename.in.new_name = sname1;
1215         status = smb_raw_rename(cli->tree, &rio);
1216         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1217
1218         /*
1219          * Reopen the stream for trans2 renames.
1220          */
1221         io.ntcreatex.in.fname = sname2;
1222         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1223         status = smb_raw_open(cli->tree, mem_ctx, &io);
1224         CHECK_STATUS(status, NT_STATUS_OK);
1225         fnum = io.ntcreatex.out.file.fnum;
1226
1227         /*
1228          * Check trans2 rename of a stream using :<stream>.
1229          */
1230         printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1231                __location__);
1232         ZERO_STRUCT(sinfo);
1233         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1234         sinfo.rename_information.in.file.fnum = fnum;
1235         sinfo.rename_information.in.overwrite = 1;
1236         sinfo.rename_information.in.root_fid = 0;
1237         sinfo.rename_information.in.new_name = stream_name1;
1238         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1239         CHECK_STATUS(status, NT_STATUS_OK);
1240
1241         /*
1242          * Check trans2 rename of an overwriting stream using :<stream>.
1243          */
1244         printf("(%s) Checking trans2 rename of an overwriting stream using "
1245                ":<stream>\n", __location__);
1246
1247         /* Create second stream. */
1248         io.ntcreatex.in.fname = sname2;
1249         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1250         status = smb_raw_open(cli->tree, mem_ctx, &io);
1251         CHECK_STATUS(status, NT_STATUS_OK);
1252         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1253
1254         /* Rename the first stream onto the second. */
1255         sinfo.rename_information.in.file.fnum = fnum;
1256         sinfo.rename_information.in.new_name = stream_name2;
1257         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1258         CHECK_STATUS(status, NT_STATUS_OK);
1259
1260         smbcli_close(cli->tree, fnum);
1261
1262         /*
1263          * Reopen the stream with the new name.
1264          */
1265         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1266         io.ntcreatex.in.fname = sname2;
1267         status = smb_raw_open(cli->tree, mem_ctx, &io);
1268         CHECK_STATUS(status, NT_STATUS_OK);
1269         fnum = io.ntcreatex.out.file.fnum;
1270
1271         /*
1272          * Check trans2 rename of a stream using <base>:<stream>.
1273          */
1274         printf("(%s) Checking trans2 rename of a stream using "
1275                "<base>:<stream>\n", __location__);
1276         sinfo.rename_information.in.file.fnum = fnum;
1277         sinfo.rename_information.in.new_name = sname1;
1278         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1279         CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1280
1281         /*
1282          * Samba3 doesn't currently support renaming a stream to the default
1283          * stream.  This test does pass on windows.
1284          */
1285         if (torture_setting_bool(tctx, "samba3", false) ||
1286             torture_setting_bool(tctx, "samba4", false)) {
1287                 goto done;
1288         }
1289
1290         /*
1291          * Check trans2 rename to the default stream using :<stream>.
1292          */
1293         printf("(%s) Checking trans2 rename to defaualt stream using "
1294                ":<stream>\n", __location__);
1295         sinfo.rename_information.in.file.fnum = fnum;
1296         sinfo.rename_information.in.new_name = stream_name_default;
1297         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1298         CHECK_STATUS(status, NT_STATUS_OK);
1299
1300         smbcli_close(cli->tree, fnum);
1301
1302  done:
1303         smbcli_close(cli->tree, fnum);
1304         status = smbcli_unlink(cli->tree, fname1);
1305         status = smbcli_unlink(cli->tree, fname2);
1306         return ret;
1307 }
1308
1309 static bool create_file_with_stream(struct torture_context *tctx,
1310                                     struct smbcli_state *cli,
1311                                     TALLOC_CTX *mem_ctx,
1312                                     const char *base_fname,
1313                                     const char *stream)
1314 {
1315         NTSTATUS status;
1316         bool ret = true;
1317         union smb_open io;
1318
1319         /* Create a file with a stream */
1320         io.generic.level = RAW_OPEN_NTCREATEX;
1321         io.ntcreatex.in.root_fid = 0;
1322         io.ntcreatex.in.flags = 0;
1323         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1324             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1325         io.ntcreatex.in.create_options = 0;
1326         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1327         io.ntcreatex.in.share_access = 0;
1328         io.ntcreatex.in.alloc_size = 0;
1329         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1330         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1331         io.ntcreatex.in.security_flags = 0;
1332         io.ntcreatex.in.fname = stream;
1333
1334         status = smb_raw_open(cli->tree, mem_ctx, &io);
1335         CHECK_STATUS(status, NT_STATUS_OK);
1336
1337  done:
1338         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1339         return ret;
1340 }
1341
1342 /* Test how streams interact with create dispositions */
1343 static bool test_stream_create_disposition(struct torture_context *tctx,
1344                                            struct smbcli_state *cli,
1345                                            TALLOC_CTX *mem_ctx)
1346 {
1347         NTSTATUS status;
1348         union smb_open io;
1349         const char *fname = BASEDIR "\\stream.txt";
1350         const char *stream = "Stream One:$DATA";
1351         const char *fname_stream;
1352         const char *default_stream_name = "::$DATA";
1353         const char *stream_list[2];
1354         bool ret = true;
1355         int fnum = -1;
1356
1357         fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1358
1359         stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
1360         stream_list[1] = default_stream_name;
1361
1362         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1363                                      fname_stream)) {
1364                 goto done;
1365         }
1366
1367         /* Open the base file with OPEN */
1368         io.generic.level = RAW_OPEN_NTCREATEX;
1369         io.ntcreatex.in.root_fid = 0;
1370         io.ntcreatex.in.flags = 0;
1371         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1372             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1373         io.ntcreatex.in.create_options = 0;
1374         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1375         io.ntcreatex.in.share_access = 0;
1376         io.ntcreatex.in.alloc_size = 0;
1377         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1378         io.ntcreatex.in.security_flags = 0;
1379         io.ntcreatex.in.fname = fname;
1380
1381         /*
1382          * check ntcreatex open: sanity check
1383          */
1384         printf("(%s) Checking ntcreatex disp: open\n", __location__);
1385         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1386         status = smb_raw_open(cli->tree, mem_ctx, &io);
1387         CHECK_STATUS(status, NT_STATUS_OK);
1388         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1389         if (!check_stream_list(cli, fname, 2, stream_list)) {
1390                 goto done;
1391         }
1392
1393         /*
1394          * check ntcreatex overwrite
1395          */
1396         printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1397         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1398         status = smb_raw_open(cli->tree, mem_ctx, &io);
1399         CHECK_STATUS(status, NT_STATUS_OK);
1400         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1401         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1402                 goto done;
1403         }
1404
1405         /*
1406          * check ntcreatex overwrite_if
1407          */
1408         printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1409         smbcli_unlink(cli->tree, fname);
1410         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1411                                      fname_stream)) {
1412                 goto done;
1413         }
1414
1415         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1416         status = smb_raw_open(cli->tree, mem_ctx, &io);
1417         CHECK_STATUS(status, NT_STATUS_OK);
1418         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1419         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1420                 goto done;
1421         }
1422
1423         /*
1424          * check ntcreatex supersede
1425          */
1426         printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1427         smbcli_unlink(cli->tree, fname);
1428         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1429                                      fname_stream)) {
1430                 goto done;
1431         }
1432
1433         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1434         status = smb_raw_open(cli->tree, mem_ctx, &io);
1435         CHECK_STATUS(status, NT_STATUS_OK);
1436         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1437         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1438                 goto done;
1439         }
1440
1441         /*
1442          * check ntcreatex overwrite_if on a stream.
1443          */
1444         printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1445                __location__);
1446         smbcli_unlink(cli->tree, fname);
1447         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1448                                      fname_stream)) {
1449                 goto done;
1450         }
1451
1452         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1453         io.ntcreatex.in.fname = fname_stream;
1454         status = smb_raw_open(cli->tree, mem_ctx, &io);
1455         CHECK_STATUS(status, NT_STATUS_OK);
1456         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1457         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1458                 goto done;
1459         }
1460
1461         /*
1462          * check openx overwrite_if
1463          */
1464         printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1465         smbcli_unlink(cli->tree, fname);
1466         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1467                                      fname_stream)) {
1468                 goto done;
1469         }
1470
1471         io.openx.level = RAW_OPEN_OPENX;
1472         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1473         io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
1474         io.openx.in.search_attrs = 0;
1475         io.openx.in.file_attrs = 0;
1476         io.openx.in.write_time = 0;
1477         io.openx.in.size = 1024*1024;
1478         io.openx.in.timeout = 0;
1479         io.openx.in.fname = fname;
1480
1481         io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1482         status = smb_raw_open(cli->tree, mem_ctx, &io);
1483         CHECK_STATUS(status, NT_STATUS_OK);
1484         smbcli_close(cli->tree, io.openx.out.file.fnum);
1485         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1486                 goto done;
1487         }
1488
1489  done:
1490         smbcli_close(cli->tree, fnum);
1491         smbcli_unlink(cli->tree, fname);
1492         return ret;
1493 }
1494
1495 /* Test streaminfo with enough streams on a file to fill up the buffer.  */
1496 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1497                                          struct smbcli_state *cli,
1498                                          TALLOC_CTX *mem_ctx)
1499 {
1500 #define LONG_STREAM_SIZE 2
1501         char *lstream_name;
1502         const char *fname = BASEDIR "\\stream.txt";
1503         const char *fname_stream;
1504         NTSTATUS status;
1505         bool ret = true;
1506         int i;
1507         union smb_fileinfo finfo;
1508
1509         lstream_name = talloc_array(mem_ctx, char, LONG_STREAM_SIZE);
1510
1511         for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1512                 lstream_name[i] = (char)('a' + i%26);
1513         }
1514         lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1515
1516         printf("(%s) Creating a file with a lot of streams\n", __location__);
1517         for (i = 0; i < 10000; i++) {
1518                 fname_stream = talloc_asprintf(mem_ctx, "%s:%s%d", fname,
1519                                                lstream_name, i);
1520                 ret = create_file_with_stream(tctx, cli, mem_ctx, fname,
1521                                               fname_stream);
1522                 if (!ret) {
1523                         goto done;
1524                 }
1525         }
1526
1527         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1528         finfo.generic.in.file.path = fname;
1529
1530         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1531         CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1532
1533  done:
1534         smbcli_unlink(cli->tree, fname);
1535         return ret;
1536 }
1537
1538 /* Test the effect of setting attributes on a stream. */
1539 static bool test_stream_attributes(struct torture_context *tctx,
1540                                          struct smbcli_state *cli,
1541                                          TALLOC_CTX *mem_ctx)
1542 {
1543         bool ret = true;
1544         NTSTATUS status;
1545         union smb_open io;
1546         const char *fname = BASEDIR "\\stream_attr.txt";
1547         const char *stream = "Stream One:$DATA";
1548         const char *fname_stream;
1549         int fnum = -1;
1550         union smb_fileinfo finfo;
1551         union smb_setfileinfo sfinfo;
1552         time_t basetime = (time(NULL) - 86400) & ~1;
1553
1554         printf ("(%s) testing attribute setting on stream\n", __location__);
1555
1556         fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1557
1558         /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1559         ret = create_file_with_stream(tctx, cli, mem_ctx, fname,
1560                                       fname_stream);
1561         if (!ret) {
1562                 goto done;
1563         }
1564
1565         ZERO_STRUCT(finfo);
1566         finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1567         finfo.generic.in.file.path = fname;
1568         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1569         CHECK_STATUS(status, NT_STATUS_OK);
1570
1571         if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1572                 printf("(%s) Incorrect attrib %x - should be %x\n", \
1573                        __location__, (unsigned int)finfo.basic_info.out.attrib,
1574                         (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1575                 ret = false;
1576                 goto done;
1577         }
1578
1579         /* Now open the stream name. */
1580
1581         io.generic.level = RAW_OPEN_NTCREATEX;
1582         io.ntcreatex.in.root_fid = 0;
1583         io.ntcreatex.in.flags = 0;
1584         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1585             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1586         io.ntcreatex.in.create_options = 0;
1587         io.ntcreatex.in.file_attr = 0;
1588         io.ntcreatex.in.share_access = 0;
1589         io.ntcreatex.in.alloc_size = 0;
1590         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1591         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1592         io.ntcreatex.in.security_flags = 0;
1593         io.ntcreatex.in.fname = fname_stream;
1594
1595         status = smb_raw_open(cli->tree, mem_ctx, &io);
1596         CHECK_STATUS(status, NT_STATUS_OK);
1597
1598         fnum = io.ntcreatex.out.file.fnum;
1599
1600         /* Change the attributes + time on the stream fnum. */
1601         ZERO_STRUCT(sfinfo);
1602         sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1603         unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1604
1605         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1606         sfinfo.generic.in.file.fnum = fnum;
1607         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1608         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { 
1609                 printf("(%s) %s - %s (should be %s)\n", __location__, "SETATTR", 
1610                         nt_errstr(status), nt_errstr(NT_STATUS_OK));
1611                 ret = false;
1612                 goto done;
1613         }
1614
1615         smbcli_close(cli->tree, fnum);
1616         fnum = -1;
1617
1618         ZERO_STRUCT(finfo);
1619         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1620         finfo.generic.in.file.path = fname;
1621         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1622         if (!NT_STATUS_IS_OK(status)) {
1623                 printf("(%s) %s pathinfo - %s\n", __location__, "SETATTRE", nt_errstr(status));
1624                 ret = false;
1625                 goto done;
1626         }
1627
1628         if (finfo.all_info.out.attrib != FILE_ATTRIBUTE_READONLY) {
1629                 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1630                         __location__,
1631                         (unsigned int)finfo.all_info.out.attrib,
1632                         (unsigned int)FILE_ATTRIBUTE_READONLY);
1633                 ret = false;
1634                 goto done;
1635         }
1636
1637         if (nt_time_to_unix(finfo.all_info.out.write_time) != basetime) {
1638                 printf("(%s) time incorrect.\n",
1639                         __location__);
1640                 ret = false;
1641                 goto done;
1642         }
1643
1644  done:
1645
1646         if (fnum != -1) {
1647                 smbcli_close(cli->tree, fnum);
1648         }
1649         smbcli_unlink(cli->tree, fname);
1650         return ret;
1651 }
1652
1653 /* 
1654    basic testing of streams calls
1655 */
1656 bool torture_raw_streams(struct torture_context *torture, 
1657                          struct smbcli_state *cli)
1658 {
1659         bool ret = true;
1660
1661         if (!torture_setup_dir(cli, BASEDIR)) {
1662                 return false;
1663         }
1664
1665         ret &= test_stream_dir(torture, cli, torture);
1666         smb_raw_exit(cli->session);
1667         ret &= test_stream_io(torture, cli, torture);
1668         smb_raw_exit(cli->session);
1669         ret &= test_stream_sharemodes(torture, cli, torture);
1670         smb_raw_exit(cli->session);
1671         if (!torture_setting_bool(torture, "samba4", false)) {
1672                 ret &= test_stream_delete(torture, cli, torture);
1673         }
1674         ret &= test_stream_names(torture, cli, torture);
1675         smb_raw_exit(cli->session);
1676         ret &= test_stream_names2(torture, cli, torture);
1677         smb_raw_exit(cli->session);
1678         ret &= test_stream_rename(torture, cli, torture);
1679         smb_raw_exit(cli->session);
1680         ret &= test_stream_rename2(torture, cli, torture);
1681         smb_raw_exit(cli->session);
1682         ret &= test_stream_create_disposition(torture, cli, torture);
1683         smb_raw_exit(cli->session);
1684
1685         ret &= test_stream_attributes(torture, cli, torture);
1686         smb_raw_exit(cli->session);
1687
1688         /* ret &= test_stream_large_streaminfo(torture, cli, torture); */
1689 /*      smb_raw_exit(cli->session); */
1690
1691         smbcli_deltree(cli->tree, BASEDIR);
1692
1693         return ret;
1694 }