6c5dc85a10580f7a1c4f1488b5cc0e633140d548
[samba.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_STD_DELETE;
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.access_mask = SEC_STD_DELETE;
1095         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1096         status = smb_raw_open(cli->tree, mem_ctx, &io);
1097         CHECK_STATUS(status, NT_STATUS_OK);
1098         fnum = io.ntcreatex.out.file.fnum;
1099
1100         /*
1101          * Now rename the second stream onto the first.
1102          */
1103
1104         ZERO_STRUCT(sfinfo);
1105
1106         sfinfo.rename_information.in.overwrite = 1;
1107         sfinfo.rename_information.in.root_fid  = 0;
1108         sfinfo.rename_information.in.new_name  = ":Stream One";
1109         CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1110
1111 done:
1112         if (fnum != -1) smbcli_close(cli->tree, fnum);
1113         status = smbcli_unlink(cli->tree, fname);
1114         return ret;
1115 }
1116
1117 static bool test_stream_rename2(struct torture_context *tctx,
1118                                struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1119 {
1120         NTSTATUS status;
1121         union smb_open io;
1122         const char *fname1 = BASEDIR "\\stream.txt";
1123         const char *fname2 = BASEDIR "\\stream2.txt";
1124         const char *stream_name1 = ":Stream One:$DATA";
1125         const char *stream_name2 = ":Stream Two:$DATA";
1126         const char *stream_name_default = "::$DATA";
1127         const char *sname1;
1128         const char *sname2;
1129         bool ret = true;
1130         int fnum = -1;
1131         union smb_setfileinfo sinfo;
1132         union smb_rename rio;
1133
1134         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
1135         sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
1136
1137         io.generic.level = RAW_OPEN_NTCREATEX;
1138         io.ntcreatex.in.root_fid = 0;
1139         io.ntcreatex.in.flags = 0;
1140         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1141             SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1142         io.ntcreatex.in.create_options = 0;
1143         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1144         io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1145                                         NTCREATEX_SHARE_ACCESS_WRITE |
1146                                         NTCREATEX_SHARE_ACCESS_DELETE);
1147         io.ntcreatex.in.alloc_size = 0;
1148         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1149         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1150         io.ntcreatex.in.security_flags = 0;
1151         io.ntcreatex.in.fname = sname1;
1152
1153         /* Open/create new stream. */
1154         status = smb_raw_open(cli->tree, mem_ctx, &io);
1155         CHECK_STATUS(status, NT_STATUS_OK);
1156
1157         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1158
1159         /*
1160          * Check raw rename with <base>:<stream>.
1161          */
1162         printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1163                __location__);
1164         rio.generic.level = RAW_RENAME_NTRENAME;
1165         rio.ntrename.in.old_name = sname1;
1166         rio.ntrename.in.new_name = sname2;
1167         rio.ntrename.in.attrib = 0;
1168         rio.ntrename.in.cluster_size = 0;
1169         rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1170         status = smb_raw_rename(cli->tree, &rio);
1171         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1172
1173         /*
1174          * Check raw rename to the default stream using :<stream>.
1175          */
1176         printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1177                __location__);
1178         rio.ntrename.in.new_name = stream_name_default;
1179         status = smb_raw_rename(cli->tree, &rio);
1180         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1181
1182         /*
1183          * Check raw rename using :<stream>.
1184          */
1185         printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1186                __location__);
1187         rio.ntrename.in.new_name = stream_name2;
1188         status = smb_raw_rename(cli->tree, &rio);
1189         CHECK_STATUS(status, NT_STATUS_OK);
1190
1191         /*
1192          * Check raw rename of a stream to a file.
1193          */
1194         printf("(%s) Checking NTRENAME of a stream to a file\n",
1195                __location__);
1196         rio.ntrename.in.old_name = sname2;
1197         rio.ntrename.in.new_name = fname2;
1198         status = smb_raw_rename(cli->tree, &rio);
1199         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1200
1201         /*
1202          * Check raw rename of a file to a stream.
1203          */
1204         printf("(%s) Checking NTRENAME of a file to a stream\n",
1205                __location__);
1206
1207         /* Create the file. */
1208         io.ntcreatex.in.fname = fname2;
1209         status = smb_raw_open(cli->tree, mem_ctx, &io);
1210         CHECK_STATUS(status, NT_STATUS_OK);
1211         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1212
1213         /* Try the rename. */
1214         rio.ntrename.in.old_name = fname2;
1215         rio.ntrename.in.new_name = sname1;
1216         status = smb_raw_rename(cli->tree, &rio);
1217         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1218
1219         /*
1220          * Reopen the stream for trans2 renames.
1221          */
1222         io.ntcreatex.in.fname = sname2;
1223         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1224         status = smb_raw_open(cli->tree, mem_ctx, &io);
1225         CHECK_STATUS(status, NT_STATUS_OK);
1226         fnum = io.ntcreatex.out.file.fnum;
1227
1228         /*
1229          * Check trans2 rename of a stream using :<stream>.
1230          */
1231         printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1232                __location__);
1233         ZERO_STRUCT(sinfo);
1234         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1235         sinfo.rename_information.in.file.fnum = fnum;
1236         sinfo.rename_information.in.overwrite = 1;
1237         sinfo.rename_information.in.root_fid = 0;
1238         sinfo.rename_information.in.new_name = stream_name1;
1239         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1240         CHECK_STATUS(status, NT_STATUS_OK);
1241
1242         /*
1243          * Check trans2 rename of an overwriting stream using :<stream>.
1244          */
1245         printf("(%s) Checking trans2 rename of an overwriting stream using "
1246                ":<stream>\n", __location__);
1247
1248         /* Create second stream. */
1249         io.ntcreatex.in.fname = sname2;
1250         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1251         status = smb_raw_open(cli->tree, mem_ctx, &io);
1252         CHECK_STATUS(status, NT_STATUS_OK);
1253         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1254
1255         /* Rename the first stream onto the second. */
1256         sinfo.rename_information.in.file.fnum = fnum;
1257         sinfo.rename_information.in.new_name = stream_name2;
1258         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1259         CHECK_STATUS(status, NT_STATUS_OK);
1260
1261         smbcli_close(cli->tree, fnum);
1262
1263         /*
1264          * Reopen the stream with the new name.
1265          */
1266         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1267         io.ntcreatex.in.fname = sname2;
1268         status = smb_raw_open(cli->tree, mem_ctx, &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 <base>:<stream>.
1274          */
1275         printf("(%s) Checking trans2 rename of a stream using "
1276                "<base>:<stream>\n", __location__);
1277         sinfo.rename_information.in.file.fnum = fnum;
1278         sinfo.rename_information.in.new_name = sname1;
1279         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1280         CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1281
1282         /*
1283          * Samba3 doesn't currently support renaming a stream to the default
1284          * stream.  This test does pass on windows.
1285          */
1286         if (torture_setting_bool(tctx, "samba3", false) ||
1287             torture_setting_bool(tctx, "samba4", false)) {
1288                 goto done;
1289         }
1290
1291         /*
1292          * Check trans2 rename to the default stream using :<stream>.
1293          */
1294         printf("(%s) Checking trans2 rename to defaualt stream using "
1295                ":<stream>\n", __location__);
1296         sinfo.rename_information.in.file.fnum = fnum;
1297         sinfo.rename_information.in.new_name = stream_name_default;
1298         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1299         CHECK_STATUS(status, NT_STATUS_OK);
1300
1301         smbcli_close(cli->tree, fnum);
1302
1303  done:
1304         smbcli_close(cli->tree, fnum);
1305         status = smbcli_unlink(cli->tree, fname1);
1306         status = smbcli_unlink(cli->tree, fname2);
1307         return ret;
1308 }
1309
1310 static bool create_file_with_stream(struct torture_context *tctx,
1311                                     struct smbcli_state *cli,
1312                                     TALLOC_CTX *mem_ctx,
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_stream)) {
1363                 goto done;
1364         }
1365
1366         /* Open the base file with OPEN */
1367         io.generic.level = RAW_OPEN_NTCREATEX;
1368         io.ntcreatex.in.root_fid = 0;
1369         io.ntcreatex.in.flags = 0;
1370         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1371             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1372         io.ntcreatex.in.create_options = 0;
1373         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1374         io.ntcreatex.in.share_access = 0;
1375         io.ntcreatex.in.alloc_size = 0;
1376         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1377         io.ntcreatex.in.security_flags = 0;
1378         io.ntcreatex.in.fname = fname;
1379
1380         /*
1381          * check ntcreatex open: sanity check
1382          */
1383         printf("(%s) Checking ntcreatex disp: open\n", __location__);
1384         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1385         status = smb_raw_open(cli->tree, mem_ctx, &io);
1386         CHECK_STATUS(status, NT_STATUS_OK);
1387         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1388         if (!check_stream_list(cli, fname, 2, stream_list)) {
1389                 goto done;
1390         }
1391
1392         /*
1393          * check ntcreatex overwrite
1394          */
1395         printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1396         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1397         status = smb_raw_open(cli->tree, mem_ctx, &io);
1398         CHECK_STATUS(status, NT_STATUS_OK);
1399         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1400         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1401                 goto done;
1402         }
1403
1404         /*
1405          * check ntcreatex overwrite_if
1406          */
1407         printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1408         smbcli_unlink(cli->tree, fname);
1409         if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
1410                 goto done;
1411         }
1412
1413         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1414         status = smb_raw_open(cli->tree, mem_ctx, &io);
1415         CHECK_STATUS(status, NT_STATUS_OK);
1416         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1417         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1418                 goto done;
1419         }
1420
1421         /*
1422          * check ntcreatex supersede
1423          */
1424         printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1425         smbcli_unlink(cli->tree, fname);
1426         if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
1427                 goto done;
1428         }
1429
1430         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1431         status = smb_raw_open(cli->tree, mem_ctx, &io);
1432         CHECK_STATUS(status, NT_STATUS_OK);
1433         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1434         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1435                 goto done;
1436         }
1437
1438         /*
1439          * check ntcreatex overwrite_if on a stream.
1440          */
1441         printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1442                __location__);
1443         smbcli_unlink(cli->tree, fname);
1444         if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
1445                 goto done;
1446         }
1447
1448         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1449         io.ntcreatex.in.fname = fname_stream;
1450         status = smb_raw_open(cli->tree, mem_ctx, &io);
1451         CHECK_STATUS(status, NT_STATUS_OK);
1452         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1453         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1454                 goto done;
1455         }
1456
1457         /*
1458          * check openx overwrite_if
1459          */
1460         printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1461         smbcli_unlink(cli->tree, fname);
1462         if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
1463                 goto done;
1464         }
1465
1466         io.openx.level = RAW_OPEN_OPENX;
1467         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1468         io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
1469         io.openx.in.search_attrs = 0;
1470         io.openx.in.file_attrs = 0;
1471         io.openx.in.write_time = 0;
1472         io.openx.in.size = 1024*1024;
1473         io.openx.in.timeout = 0;
1474         io.openx.in.fname = fname;
1475
1476         io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1477         status = smb_raw_open(cli->tree, mem_ctx, &io);
1478         CHECK_STATUS(status, NT_STATUS_OK);
1479         smbcli_close(cli->tree, io.openx.out.file.fnum);
1480         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1481                 goto done;
1482         }
1483
1484  done:
1485         smbcli_close(cli->tree, fnum);
1486         smbcli_unlink(cli->tree, fname);
1487         return ret;
1488 }
1489
1490 /* Test streaminfo with enough streams on a file to fill up the buffer.  */
1491 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1492                                          struct smbcli_state *cli,
1493                                          TALLOC_CTX *mem_ctx)
1494 {
1495 #define LONG_STREAM_SIZE 2
1496         char *lstream_name;
1497         const char *fname = BASEDIR "\\stream.txt";
1498         const char *fname_stream;
1499         NTSTATUS status;
1500         bool ret = true;
1501         int i;
1502         union smb_fileinfo finfo;
1503
1504         lstream_name = talloc_array(mem_ctx, char, LONG_STREAM_SIZE);
1505
1506         for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1507                 lstream_name[i] = (char)('a' + i%26);
1508         }
1509         lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1510
1511         printf("(%s) Creating a file with a lot of streams\n", __location__);
1512         for (i = 0; i < 10000; i++) {
1513                 fname_stream = talloc_asprintf(mem_ctx, "%s:%s%d", fname,
1514                                                lstream_name, i);
1515                 ret = create_file_with_stream(tctx, cli, mem_ctx,
1516                                               fname_stream);
1517                 if (!ret) {
1518                         goto done;
1519                 }
1520         }
1521
1522         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1523         finfo.generic.in.file.path = fname;
1524
1525         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1526         CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1527
1528  done:
1529         smbcli_unlink(cli->tree, fname);
1530         return ret;
1531 }
1532
1533 /* Test the effect of setting attributes on a stream. */
1534 static bool test_stream_attributes(struct torture_context *tctx,
1535                                          struct smbcli_state *cli,
1536                                          TALLOC_CTX *mem_ctx)
1537 {
1538         bool ret = true;
1539         NTSTATUS status;
1540         union smb_open io;
1541         const char *fname = BASEDIR "\\stream_attr.txt";
1542         const char *stream = "Stream One:$DATA";
1543         const char *fname_stream;
1544         int fnum = -1;
1545         union smb_fileinfo finfo;
1546         union smb_setfileinfo sfinfo;
1547         time_t basetime = (time(NULL) - 86400) & ~1;
1548
1549         printf ("(%s) testing attribute setting on stream\n", __location__);
1550
1551         fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1552
1553         /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1554         ret = create_file_with_stream(tctx, cli, mem_ctx, fname_stream);
1555         if (!ret) {
1556                 goto done;
1557         }
1558
1559         ZERO_STRUCT(finfo);
1560         finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1561         finfo.generic.in.file.path = fname;
1562         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1563         CHECK_STATUS(status, NT_STATUS_OK);
1564
1565         if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1566                 printf("(%s) Incorrect attrib %x - should be %x\n", \
1567                        __location__, (unsigned int)finfo.basic_info.out.attrib,
1568                         (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1569                 ret = false;
1570                 goto done;
1571         }
1572
1573         /* Now open the stream name. */
1574
1575         io.generic.level = RAW_OPEN_NTCREATEX;
1576         io.ntcreatex.in.root_fid = 0;
1577         io.ntcreatex.in.flags = 0;
1578         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1579             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1580         io.ntcreatex.in.create_options = 0;
1581         io.ntcreatex.in.file_attr = 0;
1582         io.ntcreatex.in.share_access = 0;
1583         io.ntcreatex.in.alloc_size = 0;
1584         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1585         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1586         io.ntcreatex.in.security_flags = 0;
1587         io.ntcreatex.in.fname = fname_stream;
1588
1589         status = smb_raw_open(cli->tree, mem_ctx, &io);
1590         CHECK_STATUS(status, NT_STATUS_OK);
1591
1592         fnum = io.ntcreatex.out.file.fnum;
1593
1594         /* Change the attributes + time on the stream fnum. */
1595         ZERO_STRUCT(sfinfo);
1596         sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1597         unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1598
1599         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1600         sfinfo.generic.in.file.fnum = fnum;
1601         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1602         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { 
1603                 printf("(%s) %s - %s (should be %s)\n", __location__, "SETATTR", 
1604                         nt_errstr(status), nt_errstr(NT_STATUS_OK));
1605                 ret = false;
1606                 goto done;
1607         }
1608
1609         smbcli_close(cli->tree, fnum);
1610         fnum = -1;
1611
1612         ZERO_STRUCT(finfo);
1613         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1614         finfo.generic.in.file.path = fname;
1615         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1616         if (!NT_STATUS_IS_OK(status)) {
1617                 printf("(%s) %s pathinfo - %s\n", __location__, "SETATTRE", nt_errstr(status));
1618                 ret = false;
1619                 goto done;
1620         }
1621
1622         if (finfo.all_info.out.attrib != FILE_ATTRIBUTE_READONLY) {
1623                 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1624                         __location__,
1625                         (unsigned int)finfo.all_info.out.attrib,
1626                         (unsigned int)FILE_ATTRIBUTE_READONLY);
1627                 ret = false;
1628                 goto done;
1629         }
1630
1631         if (nt_time_to_unix(finfo.all_info.out.write_time) != basetime) {
1632                 printf("(%s) time incorrect.\n",
1633                         __location__);
1634                 ret = false;
1635                 goto done;
1636         }
1637
1638  done:
1639
1640         if (fnum != -1) {
1641                 smbcli_close(cli->tree, fnum);
1642         }
1643         smbcli_unlink(cli->tree, fname);
1644         return ret;
1645 }
1646
1647 /* 
1648    basic testing of streams calls
1649 */
1650 bool torture_raw_streams(struct torture_context *torture, 
1651                          struct smbcli_state *cli)
1652 {
1653         bool ret = true;
1654
1655         if (!torture_setup_dir(cli, BASEDIR)) {
1656                 return false;
1657         }
1658
1659         ret &= test_stream_dir(torture, cli, torture);
1660         smb_raw_exit(cli->session);
1661         ret &= test_stream_io(torture, cli, torture);
1662         smb_raw_exit(cli->session);
1663         ret &= test_stream_sharemodes(torture, cli, torture);
1664         smb_raw_exit(cli->session);
1665         if (!torture_setting_bool(torture, "samba4", false)) {
1666                 ret &= test_stream_delete(torture, cli, torture);
1667         }
1668         ret &= test_stream_names(torture, cli, torture);
1669         smb_raw_exit(cli->session);
1670         ret &= test_stream_names2(torture, cli, torture);
1671         smb_raw_exit(cli->session);
1672         ret &= test_stream_rename(torture, cli, torture);
1673         smb_raw_exit(cli->session);
1674         ret &= test_stream_rename2(torture, cli, torture);
1675         smb_raw_exit(cli->session);
1676         ret &= test_stream_create_disposition(torture, cli, torture);
1677         smb_raw_exit(cli->session);
1678
1679         ret &= test_stream_attributes(torture, cli, torture);
1680         smb_raw_exit(cli->session);
1681
1682         /* ret &= test_stream_large_streaminfo(torture, cli, torture); */
1683 /*      smb_raw_exit(cli->session); */
1684
1685         smbcli_deltree(cli->tree, BASEDIR);
1686
1687         return ret;
1688 }