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