s4: allow python code to dump NTACL object as well
[Samba/ekacnet.git] / source4 / torture / raw / streams.c
bloba55575b6a3f2a359061dd0c4b96863fa77ffddd6
1 /*
2 Unix SMB/CIFS implementation.
4 test alternate data streams
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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/>.
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"
30 #define BASEDIR "\\teststreams"
32 #define CHECK_STATUS(status, correct) \
33 torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
35 #define CHECK_VALUE(v, correct) \
36 torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
38 #define CHECK_NTTIME(v, correct) \
39 torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
41 #define CHECK_STR(v, correct) do { \
42 bool ok; \
43 if ((v) && !(correct)) { \
44 ok = false; \
45 } else if (!(v) && (correct)) { \
46 ok = false; \
47 } else if (!(v) && !(correct)) { \
48 ok = true; \
49 } else if (strcmp((v), (correct)) == 0) { \
50 ok = true; \
51 } else { \
52 ok = false; \
53 } \
54 torture_assert(tctx,ok,\
55 talloc_asprintf(tctx, "got '%s', expected '%s'",\
56 (v)?(v):"NULL", (correct)?(correct):"NULL")); \
57 } while (0)
60 check that a stream has the right contents
62 static bool check_stream(struct smbcli_state *cli, const char *location,
63 TALLOC_CTX *mem_ctx,
64 const char *fname, const char *sname,
65 const char *value)
67 int fnum;
68 const char *full_name;
69 uint8_t *buf;
70 ssize_t ret;
72 full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
74 fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
76 if (value == NULL) {
77 if (fnum != -1) {
78 printf("(%s) should have failed stream open of %s\n",
79 location, full_name);
80 return false;
82 return true;
85 if (fnum == -1) {
86 printf("(%s) Failed to open stream '%s' - %s\n",
87 location, full_name, smbcli_errstr(cli->tree));
88 return false;
91 buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
93 ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
94 if (ret != strlen(value)) {
95 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
96 location, (long)strlen(value), full_name, (int)ret);
97 return false;
100 if (memcmp(buf, value, strlen(value)) != 0) {
101 printf("(%s) Bad data in stream\n", location);
102 return false;
105 smbcli_close(cli->tree, fnum);
106 return true;
109 static int qsort_string(const void *v1, const void *v2)
111 char * const *s1 = (char * const *)v1;
112 char * const *s2 = (char * const *)v2;
113 return strcmp(*s1, *s2);
116 static int qsort_stream(const void *v1, const void *v2)
118 const struct stream_struct * s1 = (const struct stream_struct *)v1;
119 const struct stream_struct * s2 = (const struct stream_struct *)v2;
120 return strcmp(s1->stream_name.s, s2->stream_name.s);
123 static bool check_stream_list(struct torture_context *tctx,
124 struct smbcli_state *cli, const char *fname,
125 int num_exp, const char **exp)
127 union smb_fileinfo finfo;
128 NTSTATUS status;
129 int i;
130 TALLOC_CTX *tmp_ctx = talloc_new(cli);
131 char **exp_sort;
132 struct stream_struct *stream_sort;
133 bool ret = false;
134 int fail = -1;
136 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
137 finfo.generic.in.file.path = fname;
139 status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
140 CHECK_STATUS(status, NT_STATUS_OK);
142 CHECK_VALUE(finfo.stream_info.out.num_streams, num_exp);
144 if (num_exp == 0) {
145 ret = true;
146 goto done;
149 exp_sort = (char **)talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
151 if (exp_sort == NULL) {
152 goto done;
155 qsort(exp_sort, num_exp, sizeof(*exp_sort), qsort_string);
157 stream_sort = (struct stream_struct *)talloc_memdup(tmp_ctx,
158 finfo.stream_info.out.streams,
159 finfo.stream_info.out.num_streams *
160 sizeof(*stream_sort));
162 if (stream_sort == NULL) {
163 goto done;
166 qsort(stream_sort, finfo.stream_info.out.num_streams,
167 sizeof(*stream_sort), qsort_stream);
169 for (i=0; i<num_exp; i++) {
170 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
171 fail = i;
172 goto show_streams;
176 ret = true;
177 done:
178 talloc_free(tmp_ctx);
179 return ret;
181 show_streams:
182 for (i=0; i<num_exp; i++) {
183 torture_comment(tctx, "stream names '%s' '%s'\n",
184 exp_sort[i], stream_sort[i].stream_name.s);
186 CHECK_STR(stream_sort[fail].stream_name.s, exp_sort[fail]);
187 talloc_free(tmp_ctx);
188 return ret;
192 test bahavior of streams on directories
194 static bool test_stream_dir(struct torture_context *tctx,
195 struct smbcli_state *cli)
197 NTSTATUS status;
198 union smb_open io;
199 const char *fname = BASEDIR "\\stream.txt";
200 const char *sname1;
201 bool ret = true;
202 const char *basedir_data;
204 if (!torture_setup_dir(cli, BASEDIR)) {
205 return false;
208 basedir_data = talloc_asprintf(tctx, "%s::$DATA", BASEDIR);
209 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
211 printf("(%s) opening non-existant directory stream\n", __location__);
212 io.generic.level = RAW_OPEN_NTCREATEX;
213 io.ntcreatex.in.root_fid.fnum = 0;
214 io.ntcreatex.in.flags = 0;
215 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
216 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
217 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
218 io.ntcreatex.in.share_access = 0;
219 io.ntcreatex.in.alloc_size = 0;
220 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
221 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
222 io.ntcreatex.in.security_flags = 0;
223 io.ntcreatex.in.fname = sname1;
224 status = smb_raw_open(cli->tree, tctx, &io);
225 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
227 printf("(%s) opening basedir stream\n", __location__);
228 io.generic.level = RAW_OPEN_NTCREATEX;
229 io.ntcreatex.in.root_fid.fnum = 0;
230 io.ntcreatex.in.flags = 0;
231 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
232 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
233 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
234 io.ntcreatex.in.share_access = 0;
235 io.ntcreatex.in.alloc_size = 0;
236 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
237 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
238 io.ntcreatex.in.security_flags = 0;
239 io.ntcreatex.in.fname = basedir_data;
240 status = smb_raw_open(cli->tree, tctx, &io);
241 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
243 printf("(%s) opening basedir ::$DATA stream\n", __location__);
244 io.generic.level = RAW_OPEN_NTCREATEX;
245 io.ntcreatex.in.root_fid.fnum = 0;
246 io.ntcreatex.in.flags = 0x10;
247 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
248 io.ntcreatex.in.create_options = 0;
249 io.ntcreatex.in.file_attr = 0;
250 io.ntcreatex.in.share_access = 0;
251 io.ntcreatex.in.alloc_size = 0;
252 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
253 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
254 io.ntcreatex.in.security_flags = 0;
255 io.ntcreatex.in.fname = basedir_data;
256 status = smb_raw_open(cli->tree, tctx, &io);
257 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
259 printf("(%s) list the streams on the basedir\n", __location__);
260 ret &= check_stream_list(tctx, cli, BASEDIR, 0, NULL);
261 done:
262 smbcli_deltree(cli->tree, BASEDIR);
263 return ret;
267 test basic behavior of streams on directories
269 static bool test_stream_io(struct torture_context *tctx,
270 struct smbcli_state *cli)
272 NTSTATUS status;
273 union smb_open io;
274 const char *fname = BASEDIR "\\stream.txt";
275 const char *sname1, *sname2;
276 bool ret = true;
277 int fnum = -1;
278 ssize_t retsize;
280 const char *one[] = { "::$DATA" };
281 const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
282 const char *three[] = { "::$DATA", ":Stream One:$DATA",
283 ":Second Stream:$DATA" };
285 if (!torture_setup_dir(cli, BASEDIR)) {
286 return false;
289 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
290 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
292 printf("(%s) creating a stream on a non-existant file\n", __location__);
293 io.generic.level = RAW_OPEN_NTCREATEX;
294 io.ntcreatex.in.root_fid.fnum = 0;
295 io.ntcreatex.in.flags = 0;
296 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
297 io.ntcreatex.in.create_options = 0;
298 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
299 io.ntcreatex.in.share_access = 0;
300 io.ntcreatex.in.alloc_size = 0;
301 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
302 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
303 io.ntcreatex.in.security_flags = 0;
304 io.ntcreatex.in.fname = sname1;
305 status = smb_raw_open(cli->tree, tctx, &io);
306 CHECK_STATUS(status, NT_STATUS_OK);
307 fnum = io.ntcreatex.out.file.fnum;
309 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", NULL);
311 printf("(%s) check that open of base file is allowed\n", __location__);
312 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
313 io.ntcreatex.in.fname = fname;
314 status = smb_raw_open(cli->tree, tctx, &io);
315 CHECK_STATUS(status, NT_STATUS_OK);
316 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
318 printf("(%s) writing to stream\n", __location__);
319 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
320 CHECK_VALUE(retsize, 9);
322 smbcli_close(cli->tree, fnum);
324 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test data");
326 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
327 io.ntcreatex.in.fname = sname1;
328 status = smb_raw_open(cli->tree, tctx, &io);
329 CHECK_STATUS(status, NT_STATUS_OK);
330 fnum = io.ntcreatex.out.file.fnum;
332 printf("(%s) modifying stream\n", __location__);
333 retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
334 CHECK_VALUE(retsize, 10);
336 smbcli_close(cli->tree, fnum);
338 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$FOO", NULL);
340 printf("(%s) creating a stream2 on a existing file\n", __location__);
341 io.ntcreatex.in.fname = sname2;
342 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
343 status = smb_raw_open(cli->tree, tctx, &io);
344 CHECK_STATUS(status, NT_STATUS_OK);
345 fnum = io.ntcreatex.out.file.fnum;
347 printf("(%s) modifying stream\n", __location__);
348 retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
349 CHECK_VALUE(retsize, 13);
351 smbcli_close(cli->tree, fnum);
353 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test MORE DATA ");
354 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$DATA", "test MORE DATA ");
355 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:", NULL);
356 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream", "SECOND STREAM");
357 ret &= check_stream(cli, __location__, tctx, fname,
358 "SECOND STREAM:$DATA", "SECOND STREAM");
359 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$DATA", "SECOND STREAM");
360 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:", NULL);
361 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$FOO", NULL);
363 check_stream_list(tctx, cli, fname, 3, three);
365 printf("(%s) deleting stream\n", __location__);
366 status = smbcli_unlink(cli->tree, sname1);
367 CHECK_STATUS(status, NT_STATUS_OK);
369 check_stream_list(tctx, cli, fname, 2, two);
371 printf("(%s) delete a stream via delete-on-close\n", __location__);
372 io.ntcreatex.in.fname = sname2;
373 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
374 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
375 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
376 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
378 status = smb_raw_open(cli->tree, tctx, &io);
379 CHECK_STATUS(status, NT_STATUS_OK);
380 fnum = io.ntcreatex.out.file.fnum;
382 smbcli_close(cli->tree, fnum);
383 status = smbcli_unlink(cli->tree, sname2);
384 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
386 check_stream_list(tctx, cli, fname, 1, one);
388 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
389 io.ntcreatex.in.fname = sname1;
390 status = smb_raw_open(cli->tree, tctx, &io);
391 CHECK_STATUS(status, NT_STATUS_OK);
392 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
393 io.ntcreatex.in.fname = sname2;
394 status = smb_raw_open(cli->tree, tctx, &io);
395 CHECK_STATUS(status, NT_STATUS_OK);
396 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
398 printf("(%s) deleting file\n", __location__);
399 status = smbcli_unlink(cli->tree, fname);
400 CHECK_STATUS(status, NT_STATUS_OK);
402 done:
403 smbcli_close(cli->tree, fnum);
404 smbcli_deltree(cli->tree, BASEDIR);
405 return ret;
409 test stream sharemodes
411 static bool test_stream_sharemodes(struct torture_context *tctx,
412 struct smbcli_state *cli)
414 NTSTATUS status;
415 union smb_open io;
416 const char *fname = BASEDIR "\\stream.txt";
417 const char *sname1, *sname2;
418 bool ret = true;
419 int fnum1 = -1;
420 int fnum2 = -1;
422 if (!torture_setup_dir(cli, BASEDIR)) {
423 return false;
426 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
427 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
429 printf("(%s) testing stream share mode conflicts\n", __location__);
430 io.generic.level = RAW_OPEN_NTCREATEX;
431 io.ntcreatex.in.root_fid.fnum = 0;
432 io.ntcreatex.in.flags = 0;
433 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
434 io.ntcreatex.in.create_options = 0;
435 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
436 io.ntcreatex.in.share_access = 0;
437 io.ntcreatex.in.alloc_size = 0;
438 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
439 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
440 io.ntcreatex.in.security_flags = 0;
441 io.ntcreatex.in.fname = sname1;
443 status = smb_raw_open(cli->tree, tctx, &io);
444 CHECK_STATUS(status, NT_STATUS_OK);
445 fnum1 = io.ntcreatex.out.file.fnum;
448 * A different stream does not give a sharing violation
451 io.ntcreatex.in.fname = sname2;
452 status = smb_raw_open(cli->tree, tctx, &io);
453 CHECK_STATUS(status, NT_STATUS_OK);
454 fnum2 = io.ntcreatex.out.file.fnum;
457 * ... whereas the same stream does with unchanged access/share_access
458 * flags
461 io.ntcreatex.in.fname = sname1;
462 io.ntcreatex.in.open_disposition = 0;
463 status = smb_raw_open(cli->tree, tctx, &io);
464 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
466 io.ntcreatex.in.fname = sname2;
467 status = smb_raw_open(cli->tree, tctx, &io);
468 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
470 done:
471 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
472 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
473 status = smbcli_unlink(cli->tree, fname);
474 smbcli_deltree(cli->tree, BASEDIR);
475 return ret;
479 * Test FILE_SHARE_DELETE on streams
481 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
482 * with SEC_STD_DELETE.
484 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
485 * be opened with SEC_STD_DELETE.
487 * A stream held open with FILE_SHARE_DELETE allows the file to be
488 * deleted. After the main file is deleted, access to the open file descriptor
489 * still works, but all name-based access to both the main file as well as the
490 * stream is denied with DELETE ending.
492 * This means, an open of the main file with SEC_STD_DELETE should walk all
493 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
494 * SHARING_VIOLATION, the main open fails.
496 * Closing the main file after delete_on_close has been set does not really
497 * unlink it but leaves the corresponding share mode entry with
498 * delete_on_close being set around until all streams are closed.
500 * Opening a stream must also look at the main file's share mode entry, look
501 * at the delete_on_close bit and potentially return DELETE_PENDING.
504 static bool test_stream_delete(struct torture_context *tctx,
505 struct smbcli_state *cli)
507 NTSTATUS status;
508 union smb_open io;
509 const char *fname = BASEDIR "\\stream.txt";
510 const char *sname1;
511 bool ret = true;
512 int fnum = -1;
513 uint8_t buf[9];
514 ssize_t retsize;
515 union smb_fileinfo finfo;
517 if (!torture_setup_dir(cli, BASEDIR)) {
518 return false;
521 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
523 printf("(%s) opening non-existant file stream\n", __location__);
524 io.generic.level = RAW_OPEN_NTCREATEX;
525 io.ntcreatex.in.root_fid.fnum = 0;
526 io.ntcreatex.in.flags = 0;
527 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
528 io.ntcreatex.in.create_options = 0;
529 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
530 io.ntcreatex.in.share_access = 0;
531 io.ntcreatex.in.alloc_size = 0;
532 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
533 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
534 io.ntcreatex.in.security_flags = 0;
535 io.ntcreatex.in.fname = sname1;
537 status = smb_raw_open(cli->tree, tctx, &io);
538 CHECK_STATUS(status, NT_STATUS_OK);
539 fnum = io.ntcreatex.out.file.fnum;
541 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
542 CHECK_VALUE(retsize, 9);
545 * One stream opened without FILE_SHARE_DELETE prevents the main file
546 * to be deleted or even opened with DELETE access
549 status = smbcli_unlink(cli->tree, fname);
550 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
552 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
553 io.ntcreatex.in.fname = fname;
554 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
555 status = smb_raw_open(cli->tree, tctx, &io);
556 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
558 smbcli_close(cli->tree, fnum);
561 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
564 io.ntcreatex.in.fname = sname1;
565 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
566 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
567 status = smb_raw_open(cli->tree, tctx, &io);
568 CHECK_STATUS(status, NT_STATUS_OK);
569 fnum = io.ntcreatex.out.file.fnum;
571 status = smbcli_unlink(cli->tree, fname);
572 CHECK_STATUS(status, NT_STATUS_OK);
575 * file access still works on the stream while the main file is closed
578 retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
579 CHECK_VALUE(retsize, 9);
581 finfo.generic.level = RAW_FILEINFO_STANDARD;
582 finfo.generic.in.file.path = fname;
585 * name-based access to both the main file and the stream does not
586 * work anymore but gives DELETE_PENDING
589 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
590 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
593 * older S3 doesn't do this
595 finfo.generic.in.file.path = sname1;
596 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
597 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
600 * fd-based qfileinfo on the stream still works, the stream does not
601 * have the delete-on-close bit set. This could mean that open on the
602 * stream first opens the main file
605 finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
606 finfo.all_info.in.file.fnum = fnum;
608 status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
609 CHECK_STATUS(status, NT_STATUS_OK);
611 /* w2k and w2k3 return 0 and w2k8 returns 1 */
612 if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) ||
613 TARGET_IS_SAMBA3(tctx)) {
614 CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
615 } else {
616 CHECK_VALUE(finfo.all_info.out.delete_pending, 1);
619 smbcli_close(cli->tree, fnum);
622 * After closing the stream the file is really gone.
625 finfo.generic.in.file.path = fname;
626 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
627 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
629 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA
630 |SEC_STD_DELETE;
631 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
632 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
633 status = smb_raw_open(cli->tree, tctx, &io);
634 CHECK_STATUS(status, NT_STATUS_OK);
635 fnum = io.ntcreatex.out.file.fnum;
637 finfo.generic.in.file.path = fname;
638 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
639 CHECK_STATUS(status, NT_STATUS_OK);
641 smbcli_close(cli->tree, fnum);
643 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
644 CHECK_STATUS(status, NT_STATUS_OK);
645 done:
646 smbcli_close(cli->tree, fnum);
647 smbcli_unlink(cli->tree, fname);
648 smbcli_deltree(cli->tree, BASEDIR);
649 return ret;
653 test stream names
655 static bool test_stream_names(struct torture_context *tctx,
656 struct smbcli_state *cli)
658 NTSTATUS status;
659 union smb_open io;
660 union smb_fileinfo finfo;
661 union smb_fileinfo stinfo;
662 union smb_setfileinfo sinfo;
663 const char *fname = BASEDIR "\\stream_names.txt";
664 const char *sname1, *sname1b, *sname1c, *sname1d;
665 const char *sname2, *snamew, *snamew2;
666 const char *snamer1, *snamer2;
667 bool ret = true;
668 int fnum1 = -1;
669 int fnum2 = -1;
670 int fnum3 = -1;
671 int i;
672 const char *four[4] = {
673 "::$DATA",
674 ":\x05Stream\n One:$DATA",
675 ":MStream Two:$DATA",
676 ":?Stream*:$DATA"
678 const char *five1[5] = {
679 "::$DATA",
680 ":\x05Stream\n One:$DATA",
681 ":BeforeRename:$DATA",
682 ":MStream Two:$DATA",
683 ":?Stream*:$DATA"
685 const char *five2[5] = {
686 "::$DATA",
687 ":\x05Stream\n One:$DATA",
688 ":AfterRename:$DATA",
689 ":MStream Two:$DATA",
690 ":?Stream*:$DATA"
693 if (!torture_setup_dir(cli, BASEDIR)) {
694 return false;
697 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
698 sname1b = talloc_asprintf(tctx, "%s:", sname1);
699 sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
700 sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
701 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
702 snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
703 snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
704 snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
705 snamer2 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "AfterRename");
707 printf("(%s) testing stream names\n", __location__);
708 io.generic.level = RAW_OPEN_NTCREATEX;
709 io.ntcreatex.in.root_fid.fnum = 0;
710 io.ntcreatex.in.flags = 0;
711 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
712 io.ntcreatex.in.create_options = 0;
713 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
714 io.ntcreatex.in.share_access = 0;
715 io.ntcreatex.in.alloc_size = 0;
716 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
717 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
718 io.ntcreatex.in.security_flags = 0;
719 io.ntcreatex.in.fname = fname;
721 status = smb_raw_open(cli->tree, tctx, &io);
722 CHECK_STATUS(status, NT_STATUS_OK);
723 fnum1 = io.ntcreatex.out.file.fnum;
726 * Make sure the create time of the streams are different from the
727 * base file.
729 sleep(2);
730 smbcli_close(cli->tree, fnum1);
732 io.generic.level = RAW_OPEN_NTCREATEX;
733 io.ntcreatex.in.root_fid.fnum = 0;
734 io.ntcreatex.in.flags = 0;
735 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
736 io.ntcreatex.in.create_options = 0;
737 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
738 io.ntcreatex.in.share_access = 0;
739 io.ntcreatex.in.alloc_size = 0;
740 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
741 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
742 io.ntcreatex.in.security_flags = 0;
743 io.ntcreatex.in.fname = sname1;
745 status = smb_raw_open(cli->tree, tctx, &io);
746 CHECK_STATUS(status, NT_STATUS_OK);
747 fnum1 = io.ntcreatex.out.file.fnum;
750 * A different stream does not give a sharing violation
753 io.ntcreatex.in.fname = sname2;
754 status = smb_raw_open(cli->tree, tctx, &io);
755 CHECK_STATUS(status, NT_STATUS_OK);
756 fnum2 = io.ntcreatex.out.file.fnum;
759 * ... whereas the same stream does with unchanged access/share_access
760 * flags
763 io.ntcreatex.in.fname = sname1;
764 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
765 status = smb_raw_open(cli->tree, tctx, &io);
766 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
768 io.ntcreatex.in.fname = sname1b;
769 status = smb_raw_open(cli->tree, tctx, &io);
770 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
772 io.ntcreatex.in.fname = sname1c;
773 status = smb_raw_open(cli->tree, tctx, &io);
774 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
775 /* w2k returns INVALID_PARAMETER */
776 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
777 } else {
778 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
781 io.ntcreatex.in.fname = sname1d;
782 status = smb_raw_open(cli->tree, tctx, &io);
783 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
784 /* w2k returns INVALID_PARAMETER */
785 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
786 } else {
787 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
790 io.ntcreatex.in.fname = sname2;
791 status = smb_raw_open(cli->tree, tctx, &io);
792 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
794 io.ntcreatex.in.fname = snamew;
795 status = smb_raw_open(cli->tree, tctx, &io);
796 CHECK_STATUS(status, NT_STATUS_OK);
797 fnum3 = io.ntcreatex.out.file.fnum;
799 io.ntcreatex.in.fname = snamew2;
800 status = smb_raw_open(cli->tree, tctx, &io);
801 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
803 ret &= check_stream_list(tctx, cli, fname, 4, four);
805 smbcli_close(cli->tree, fnum1);
806 smbcli_close(cli->tree, fnum2);
807 smbcli_close(cli->tree, fnum3);
809 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
810 finfo.generic.in.file.path = fname;
811 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
812 CHECK_STATUS(status, NT_STATUS_OK);
814 ret &= check_stream_list(tctx, cli, fname, 4, four);
816 for (i=0; i < 4; i++) {
817 NTTIME write_time;
818 uint64_t stream_size;
819 char *path = talloc_asprintf(tctx, "%s%s",
820 fname, four[i]);
822 char *rpath = talloc_strdup(path, path);
823 char *p = strrchr(rpath, ':');
824 /* eat :$DATA */
825 *p = 0;
826 p--;
827 if (*p == ':') {
828 /* eat ::$DATA */
829 *p = 0;
831 printf("(%s): i[%u][%s]\n", __location__, i, path);
832 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
833 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
834 SEC_FILE_WRITE_ATTRIBUTE |
835 SEC_RIGHTS_FILE_ALL;
836 io.ntcreatex.in.fname = path;
837 status = smb_raw_open(cli->tree, tctx, &io);
838 CHECK_STATUS(status, NT_STATUS_OK);
839 fnum1 = io.ntcreatex.out.file.fnum;
841 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
842 finfo.generic.in.file.path = fname;
843 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
844 CHECK_STATUS(status, NT_STATUS_OK);
846 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
847 stinfo.generic.in.file.fnum = fnum1;
848 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
849 CHECK_STATUS(status, NT_STATUS_OK);
850 if (!torture_setting_bool(tctx, "samba3", false)) {
851 CHECK_NTTIME(stinfo.all_info.out.create_time,
852 finfo.all_info.out.create_time);
853 CHECK_NTTIME(stinfo.all_info.out.access_time,
854 finfo.all_info.out.access_time);
855 CHECK_NTTIME(stinfo.all_info.out.write_time,
856 finfo.all_info.out.write_time);
857 CHECK_NTTIME(stinfo.all_info.out.change_time,
858 finfo.all_info.out.change_time);
860 CHECK_VALUE(stinfo.all_info.out.attrib,
861 finfo.all_info.out.attrib);
862 CHECK_VALUE(stinfo.all_info.out.size,
863 finfo.all_info.out.size);
864 CHECK_VALUE(stinfo.all_info.out.delete_pending,
865 finfo.all_info.out.delete_pending);
866 CHECK_VALUE(stinfo.all_info.out.directory,
867 finfo.all_info.out.directory);
868 CHECK_VALUE(stinfo.all_info.out.ea_size,
869 finfo.all_info.out.ea_size);
871 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
872 stinfo.generic.in.file.fnum = fnum1;
873 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
874 CHECK_STATUS(status, NT_STATUS_OK);
875 if (!torture_setting_bool(tctx, "samba3", false)) {
876 CHECK_STR(stinfo.name_info.out.fname.s, rpath);
879 write_time = finfo.all_info.out.write_time;
880 write_time += i*1000000;
881 write_time /= 1000000;
882 write_time *= 1000000;
884 ZERO_STRUCT(sinfo);
885 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
886 sinfo.basic_info.in.file.fnum = fnum1;
887 sinfo.basic_info.in.write_time = write_time;
888 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
889 status = smb_raw_setfileinfo(cli->tree, &sinfo);
890 CHECK_STATUS(status, NT_STATUS_OK);
892 stream_size = i*8192;
894 ZERO_STRUCT(sinfo);
895 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
896 sinfo.end_of_file_info.in.file.fnum = fnum1;
897 sinfo.end_of_file_info.in.size = stream_size;
898 status = smb_raw_setfileinfo(cli->tree, &sinfo);
899 CHECK_STATUS(status, NT_STATUS_OK);
901 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
902 stinfo.generic.in.file.fnum = fnum1;
903 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
904 CHECK_STATUS(status, NT_STATUS_OK);
905 if (!torture_setting_bool(tctx, "samba3", false)) {
906 CHECK_NTTIME(stinfo.all_info.out.write_time,
907 write_time);
908 CHECK_VALUE(stinfo.all_info.out.attrib,
909 finfo.all_info.out.attrib);
911 CHECK_VALUE(stinfo.all_info.out.size,
912 stream_size);
913 CHECK_VALUE(stinfo.all_info.out.delete_pending,
914 finfo.all_info.out.delete_pending);
915 CHECK_VALUE(stinfo.all_info.out.directory,
916 finfo.all_info.out.directory);
917 CHECK_VALUE(stinfo.all_info.out.ea_size,
918 finfo.all_info.out.ea_size);
920 ret &= check_stream_list(tctx, cli, fname, 4, four);
922 smbcli_close(cli->tree, fnum1);
923 talloc_free(path);
926 printf("(%s): testing stream renames\n", __location__);
927 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
928 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
929 SEC_FILE_WRITE_ATTRIBUTE |
930 SEC_RIGHTS_FILE_ALL;
931 io.ntcreatex.in.fname = snamer1;
932 status = smb_raw_open(cli->tree, tctx, &io);
933 CHECK_STATUS(status, NT_STATUS_OK);
934 fnum1 = io.ntcreatex.out.file.fnum;
936 ret &= check_stream_list(tctx, cli, fname, 5, five1);
938 ZERO_STRUCT(sinfo);
939 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
940 sinfo.rename_information.in.file.fnum = fnum1;
941 sinfo.rename_information.in.overwrite = true;
942 sinfo.rename_information.in.root_fid = 0;
943 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
944 status = smb_raw_setfileinfo(cli->tree, &sinfo);
945 CHECK_STATUS(status, NT_STATUS_OK);
947 ret &= check_stream_list(tctx, cli, fname, 5, five2);
949 ZERO_STRUCT(sinfo);
950 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
951 sinfo.rename_information.in.file.fnum = fnum1;
952 sinfo.rename_information.in.overwrite = false;
953 sinfo.rename_information.in.root_fid = 0;
954 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
955 status = smb_raw_setfileinfo(cli->tree, &sinfo);
956 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
958 ret &= check_stream_list(tctx, cli, fname, 5, five2);
960 ZERO_STRUCT(sinfo);
961 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
962 sinfo.rename_information.in.file.fnum = fnum1;
963 sinfo.rename_information.in.overwrite = true;
964 sinfo.rename_information.in.root_fid = 0;
965 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
966 status = smb_raw_setfileinfo(cli->tree, &sinfo);
967 if (torture_setting_bool(tctx, "samba4", false) ||
968 torture_setting_bool(tctx, "samba3", false)) {
969 /* why should this rename be considered invalid?? */
970 CHECK_STATUS(status, NT_STATUS_OK);
971 ret &= check_stream_list(tctx, cli, fname, 4, four);
972 } else {
973 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
974 ret &= check_stream_list(tctx, cli, fname, 5, five2);
978 /* TODO: we need to test more rename combinations */
980 done:
981 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
982 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
983 if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
984 status = smbcli_unlink(cli->tree, fname);
985 smbcli_deltree(cli->tree, BASEDIR);
986 return ret;
990 test stream names
992 static bool test_stream_names2(struct torture_context *tctx,
993 struct smbcli_state *cli)
995 NTSTATUS status;
996 union smb_open io;
997 const char *fname = BASEDIR "\\stream_names2.txt";
998 bool ret = true;
999 int fnum1 = -1;
1000 uint8_t i;
1002 if (!torture_setup_dir(cli, BASEDIR)) {
1003 return false;
1006 printf("(%s) testing stream names\n", __location__);
1007 io.generic.level = RAW_OPEN_NTCREATEX;
1008 io.ntcreatex.in.root_fid.fnum = 0;
1009 io.ntcreatex.in.flags = 0;
1010 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1011 io.ntcreatex.in.create_options = 0;
1012 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1013 io.ntcreatex.in.share_access = 0;
1014 io.ntcreatex.in.alloc_size = 0;
1015 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1016 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1017 io.ntcreatex.in.security_flags = 0;
1018 io.ntcreatex.in.fname = fname;
1019 status = smb_raw_open(cli->tree, tctx, &io);
1020 CHECK_STATUS(status, NT_STATUS_OK);
1021 fnum1 = io.ntcreatex.out.file.fnum;
1023 for (i=0x01; i < 0x7F; i++) {
1024 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1025 fname, i, i);
1026 NTSTATUS expected;
1028 switch (i) {
1029 case '/':/*0x2F*/
1030 case ':':/*0x3A*/
1031 case '\\':/*0x5C*/
1032 expected = NT_STATUS_OBJECT_NAME_INVALID;
1033 break;
1034 default:
1035 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1036 break;
1040 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1041 io.ntcreatex.in.fname = path;
1042 status = smb_raw_open(cli->tree, tctx, &io);
1043 if (!NT_STATUS_EQUAL(status, expected)) {
1044 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1045 __location__, fname, isprint(i)?(char)i:' ', i,
1046 isprint(i)?"":" (not printable)",
1047 nt_errstr(expected));
1049 CHECK_STATUS(status, expected);
1051 talloc_free(path);
1054 done:
1055 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1056 status = smbcli_unlink(cli->tree, fname);
1057 smbcli_deltree(cli->tree, BASEDIR);
1058 return ret;
1061 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1062 check_fnum = true; \
1063 call_name = #call; \
1064 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1065 sfinfo.generic.in.file.fnum = fnum; \
1066 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1067 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1068 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1069 nt_errstr(status), nt_errstr(rightstatus)); \
1070 ret = false; \
1072 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1073 finfo1.generic.in.file.fnum = fnum; \
1074 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1075 if (!NT_STATUS_IS_OK(status2)) { \
1076 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1077 ret = false; \
1078 }} while (0)
1081 test stream renames
1083 static bool test_stream_rename(struct torture_context *tctx,
1084 struct smbcli_state *cli)
1086 NTSTATUS status, status2;
1087 union smb_open io;
1088 const char *fname = BASEDIR "\\stream_rename.txt";
1089 const char *sname1, *sname2;
1090 union smb_fileinfo finfo1;
1091 union smb_setfileinfo sfinfo;
1092 bool ret = true;
1093 int fnum = -1;
1094 bool check_fnum;
1095 const char *call_name;
1097 if (!torture_setup_dir(cli, BASEDIR)) {
1098 return false;
1101 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1102 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1104 printf("(%s) testing stream renames\n", __location__);
1105 io.generic.level = RAW_OPEN_NTCREATEX;
1106 io.ntcreatex.in.root_fid.fnum = 0;
1107 io.ntcreatex.in.flags = 0;
1108 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1109 SEC_FILE_WRITE_ATTRIBUTE |
1110 SEC_RIGHTS_FILE_ALL;
1111 io.ntcreatex.in.create_options = 0;
1112 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1113 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1114 io.ntcreatex.in.alloc_size = 0;
1115 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1116 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1117 io.ntcreatex.in.security_flags = 0;
1118 io.ntcreatex.in.fname = sname1;
1120 /* Create two streams. */
1121 status = smb_raw_open(cli->tree, tctx, &io);
1122 CHECK_STATUS(status, NT_STATUS_OK);
1123 fnum = io.ntcreatex.out.file.fnum;
1124 if (fnum != -1) smbcli_close(cli->tree, fnum);
1126 io.ntcreatex.in.fname = sname2;
1127 status = smb_raw_open(cli->tree, tctx, &io);
1128 CHECK_STATUS(status, NT_STATUS_OK);
1129 fnum = io.ntcreatex.out.file.fnum;
1131 if (fnum != -1) smbcli_close(cli->tree, fnum);
1134 * Open the second stream.
1137 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1138 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1139 status = smb_raw_open(cli->tree, tctx, &io);
1140 CHECK_STATUS(status, NT_STATUS_OK);
1141 fnum = io.ntcreatex.out.file.fnum;
1144 * Now rename the second stream onto the first.
1147 ZERO_STRUCT(sfinfo);
1149 sfinfo.rename_information.in.overwrite = 1;
1150 sfinfo.rename_information.in.root_fid = 0;
1151 sfinfo.rename_information.in.new_name = ":Stream One";
1152 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1154 done:
1155 if (fnum != -1) smbcli_close(cli->tree, fnum);
1156 status = smbcli_unlink(cli->tree, fname);
1157 smbcli_deltree(cli->tree, BASEDIR);
1158 return ret;
1161 static bool test_stream_rename2(struct torture_context *tctx,
1162 struct smbcli_state *cli)
1164 NTSTATUS status;
1165 union smb_open io;
1166 const char *fname1 = BASEDIR "\\stream.txt";
1167 const char *fname2 = BASEDIR "\\stream2.txt";
1168 const char *stream_name1 = ":Stream One:$DATA";
1169 const char *stream_name2 = ":Stream Two:$DATA";
1170 const char *stream_name_default = "::$DATA";
1171 const char *sname1;
1172 const char *sname2;
1173 bool ret = true;
1174 int fnum = -1;
1175 union smb_setfileinfo sinfo;
1176 union smb_rename rio;
1178 if (!torture_setup_dir(cli, BASEDIR)) {
1179 return false;
1182 sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1183 sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1185 io.generic.level = RAW_OPEN_NTCREATEX;
1186 io.ntcreatex.in.root_fid.fnum = 0;
1187 io.ntcreatex.in.flags = 0;
1188 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1189 SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1190 io.ntcreatex.in.create_options = 0;
1191 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1192 io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1193 NTCREATEX_SHARE_ACCESS_WRITE |
1194 NTCREATEX_SHARE_ACCESS_DELETE);
1195 io.ntcreatex.in.alloc_size = 0;
1196 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1197 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1198 io.ntcreatex.in.security_flags = 0;
1199 io.ntcreatex.in.fname = sname1;
1201 /* Open/create new stream. */
1202 status = smb_raw_open(cli->tree, tctx, &io);
1203 CHECK_STATUS(status, NT_STATUS_OK);
1205 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1208 * Check raw rename with <base>:<stream>.
1210 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1211 __location__);
1212 rio.generic.level = RAW_RENAME_NTRENAME;
1213 rio.ntrename.in.old_name = sname1;
1214 rio.ntrename.in.new_name = sname2;
1215 rio.ntrename.in.attrib = 0;
1216 rio.ntrename.in.cluster_size = 0;
1217 rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1218 status = smb_raw_rename(cli->tree, &rio);
1219 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1222 * Check raw rename to the default stream using :<stream>.
1224 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1225 __location__);
1226 rio.ntrename.in.new_name = stream_name_default;
1227 status = smb_raw_rename(cli->tree, &rio);
1228 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1231 * Check raw rename using :<stream>.
1233 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1234 __location__);
1235 rio.ntrename.in.new_name = stream_name2;
1236 status = smb_raw_rename(cli->tree, &rio);
1237 CHECK_STATUS(status, NT_STATUS_OK);
1240 * Check raw rename of a stream to a file.
1242 printf("(%s) Checking NTRENAME of a stream to a file\n",
1243 __location__);
1244 rio.ntrename.in.old_name = sname2;
1245 rio.ntrename.in.new_name = fname2;
1246 status = smb_raw_rename(cli->tree, &rio);
1247 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1250 * Check raw rename of a file to a stream.
1252 printf("(%s) Checking NTRENAME of a file to a stream\n",
1253 __location__);
1255 /* Create the file. */
1256 io.ntcreatex.in.fname = fname2;
1257 status = smb_raw_open(cli->tree, tctx, &io);
1258 CHECK_STATUS(status, NT_STATUS_OK);
1259 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1261 /* Try the rename. */
1262 rio.ntrename.in.old_name = fname2;
1263 rio.ntrename.in.new_name = sname1;
1264 status = smb_raw_rename(cli->tree, &rio);
1265 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1268 * Reopen the stream for trans2 renames.
1270 io.ntcreatex.in.fname = sname2;
1271 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1272 status = smb_raw_open(cli->tree, tctx, &io);
1273 CHECK_STATUS(status, NT_STATUS_OK);
1274 fnum = io.ntcreatex.out.file.fnum;
1277 * Check trans2 rename of a stream using :<stream>.
1279 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1280 __location__);
1281 ZERO_STRUCT(sinfo);
1282 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1283 sinfo.rename_information.in.file.fnum = fnum;
1284 sinfo.rename_information.in.overwrite = 1;
1285 sinfo.rename_information.in.root_fid = 0;
1286 sinfo.rename_information.in.new_name = stream_name1;
1287 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1288 CHECK_STATUS(status, NT_STATUS_OK);
1291 * Check trans2 rename of an overwriting stream using :<stream>.
1293 printf("(%s) Checking trans2 rename of an overwriting stream using "
1294 ":<stream>\n", __location__);
1296 /* Create second stream. */
1297 io.ntcreatex.in.fname = sname2;
1298 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1299 status = smb_raw_open(cli->tree, tctx, &io);
1300 CHECK_STATUS(status, NT_STATUS_OK);
1301 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1303 /* Rename the first stream onto the second. */
1304 sinfo.rename_information.in.file.fnum = fnum;
1305 sinfo.rename_information.in.new_name = stream_name2;
1306 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1307 CHECK_STATUS(status, NT_STATUS_OK);
1309 smbcli_close(cli->tree, fnum);
1312 * Reopen the stream with the new name.
1314 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1315 io.ntcreatex.in.fname = sname2;
1316 status = smb_raw_open(cli->tree, tctx, &io);
1317 CHECK_STATUS(status, NT_STATUS_OK);
1318 fnum = io.ntcreatex.out.file.fnum;
1321 * Check trans2 rename of a stream using <base>:<stream>.
1323 printf("(%s) Checking trans2 rename of a stream using "
1324 "<base>:<stream>\n", __location__);
1325 sinfo.rename_information.in.file.fnum = fnum;
1326 sinfo.rename_information.in.new_name = sname1;
1327 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1328 CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1331 * Samba3 doesn't currently support renaming a stream to the default
1332 * stream. This test does pass on windows.
1334 if (torture_setting_bool(tctx, "samba3", false) ||
1335 torture_setting_bool(tctx, "samba4", false)) {
1336 goto done;
1340 * Check trans2 rename to the default stream using :<stream>.
1342 printf("(%s) Checking trans2 rename to defaualt stream using "
1343 ":<stream>\n", __location__);
1344 sinfo.rename_information.in.file.fnum = fnum;
1345 sinfo.rename_information.in.new_name = stream_name_default;
1346 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1347 CHECK_STATUS(status, NT_STATUS_OK);
1349 smbcli_close(cli->tree, fnum);
1351 done:
1352 smbcli_close(cli->tree, fnum);
1353 status = smbcli_unlink(cli->tree, fname1);
1354 status = smbcli_unlink(cli->tree, fname2);
1355 smbcli_deltree(cli->tree, BASEDIR);
1356 return ret;
1360 test stream renames
1362 static bool test_stream_rename3(struct torture_context *tctx,
1363 struct smbcli_state *cli)
1365 NTSTATUS status, status2;
1366 union smb_open io;
1367 const char *fname = BASEDIR "\\stream_rename.txt";
1368 const char *sname1, *sname2;
1369 union smb_fileinfo finfo1;
1370 union smb_setfileinfo sfinfo;
1371 bool ret = true;
1372 int fnum = -1;
1373 int fnum2 = -1;
1374 bool check_fnum;
1375 const char *call_name;
1377 if (!torture_setup_dir(cli, BASEDIR)) {
1378 return false;
1381 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1382 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1384 printf("(%s) testing stream renames\n", __location__);
1385 io.generic.level = RAW_OPEN_NTCREATEX;
1386 io.ntcreatex.in.root_fid.fnum = 0;
1387 io.ntcreatex.in.flags = 0;
1388 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1389 SEC_FILE_WRITE_ATTRIBUTE |
1390 SEC_RIGHTS_FILE_ALL;
1391 io.ntcreatex.in.create_options = 0;
1392 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1393 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1394 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1395 io.ntcreatex.in.alloc_size = 0;
1396 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1397 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1398 io.ntcreatex.in.security_flags = 0;
1399 io.ntcreatex.in.fname = sname1;
1401 /* Create two streams. */
1402 status = smb_raw_open(cli->tree, tctx, &io);
1403 CHECK_STATUS(status, NT_STATUS_OK);
1404 fnum = io.ntcreatex.out.file.fnum;
1405 if (fnum != -1) smbcli_close(cli->tree, fnum);
1407 io.ntcreatex.in.fname = sname2;
1408 status = smb_raw_open(cli->tree, tctx, &io);
1409 CHECK_STATUS(status, NT_STATUS_OK);
1410 fnum = io.ntcreatex.out.file.fnum;
1412 if (fnum != -1) smbcli_close(cli->tree, fnum);
1414 /* open the second stream. */
1415 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1416 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1417 status = smb_raw_open(cli->tree, tctx, &io);
1418 CHECK_STATUS(status, NT_STATUS_OK);
1419 fnum = io.ntcreatex.out.file.fnum;
1421 /* Keep a handle to the first stream open. */
1422 io.ntcreatex.in.fname = sname1;
1423 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1424 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1425 status = smb_raw_open(cli->tree, tctx, &io);
1426 CHECK_STATUS(status, NT_STATUS_OK);
1427 fnum2 = io.ntcreatex.out.file.fnum;
1429 ZERO_STRUCT(sfinfo);
1430 sfinfo.rename_information.in.overwrite = 1;
1431 sfinfo.rename_information.in.root_fid = 0;
1432 sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1433 if (torture_setting_bool(tctx, "samba4", false) ||
1434 torture_setting_bool(tctx, "samba3", false)) {
1435 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1436 } else {
1437 CHECK_CALL_FNUM(RENAME_INFORMATION,
1438 NT_STATUS_INVALID_PARAMETER);
1442 done:
1443 if (fnum != -1) smbcli_close(cli->tree, fnum);
1444 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1445 status = smbcli_unlink(cli->tree, fname);
1446 smbcli_deltree(cli->tree, BASEDIR);
1447 return ret;
1450 static bool create_file_with_stream(struct torture_context *tctx,
1451 struct smbcli_state *cli,
1452 const char *stream)
1454 NTSTATUS status;
1455 bool ret = true;
1456 union smb_open io;
1458 /* Create a file with a stream */
1459 io.generic.level = RAW_OPEN_NTCREATEX;
1460 io.ntcreatex.in.root_fid.fnum = 0;
1461 io.ntcreatex.in.flags = 0;
1462 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1463 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1464 io.ntcreatex.in.create_options = 0;
1465 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1466 io.ntcreatex.in.share_access = 0;
1467 io.ntcreatex.in.alloc_size = 0;
1468 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1469 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1470 io.ntcreatex.in.security_flags = 0;
1471 io.ntcreatex.in.fname = stream;
1473 status = smb_raw_open(cli->tree, tctx, &io);
1474 CHECK_STATUS(status, NT_STATUS_OK);
1476 done:
1477 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1478 return ret;
1481 /* Test how streams interact with create dispositions */
1482 static bool test_stream_create_disposition(struct torture_context *tctx,
1483 struct smbcli_state *cli)
1485 NTSTATUS status;
1486 union smb_open io;
1487 const char *fname = BASEDIR "\\stream.txt";
1488 const char *stream = "Stream One:$DATA";
1489 const char *fname_stream;
1490 const char *default_stream_name = "::$DATA";
1491 const char *stream_list[2];
1492 bool ret = false;
1493 int fnum = -1;
1495 if (!torture_setup_dir(cli, BASEDIR)) {
1496 return false;
1499 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1501 stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1502 stream_list[1] = default_stream_name;
1504 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1505 goto done;
1508 /* Open the base file with OPEN */
1509 io.generic.level = RAW_OPEN_NTCREATEX;
1510 io.ntcreatex.in.root_fid.fnum = 0;
1511 io.ntcreatex.in.flags = 0;
1512 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1513 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1514 io.ntcreatex.in.create_options = 0;
1515 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1516 io.ntcreatex.in.share_access = 0;
1517 io.ntcreatex.in.alloc_size = 0;
1518 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1519 io.ntcreatex.in.security_flags = 0;
1520 io.ntcreatex.in.fname = fname;
1523 * check ntcreatex open: sanity check
1525 printf("(%s) Checking ntcreatex disp: open\n", __location__);
1526 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1527 status = smb_raw_open(cli->tree, tctx, &io);
1528 CHECK_STATUS(status, NT_STATUS_OK);
1529 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1530 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1531 goto done;
1535 * check ntcreatex overwrite
1537 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1538 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1539 status = smb_raw_open(cli->tree, tctx, &io);
1540 CHECK_STATUS(status, NT_STATUS_OK);
1541 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1542 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1543 goto done;
1547 * check ntcreatex overwrite_if
1549 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1550 smbcli_unlink(cli->tree, fname);
1551 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1552 goto done;
1555 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1556 status = smb_raw_open(cli->tree, tctx, &io);
1557 CHECK_STATUS(status, NT_STATUS_OK);
1558 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1559 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1560 goto done;
1564 * check ntcreatex supersede
1566 printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1567 smbcli_unlink(cli->tree, fname);
1568 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1569 goto done;
1572 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1573 status = smb_raw_open(cli->tree, tctx, &io);
1574 CHECK_STATUS(status, NT_STATUS_OK);
1575 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1576 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1577 goto done;
1581 * check ntcreatex overwrite_if on a stream.
1583 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1584 __location__);
1585 smbcli_unlink(cli->tree, fname);
1586 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1587 goto done;
1590 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1591 io.ntcreatex.in.fname = fname_stream;
1592 status = smb_raw_open(cli->tree, tctx, &io);
1593 CHECK_STATUS(status, NT_STATUS_OK);
1594 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1595 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1596 goto done;
1600 * check openx overwrite_if
1602 printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1603 smbcli_unlink(cli->tree, fname);
1604 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1605 goto done;
1608 io.openx.level = RAW_OPEN_OPENX;
1609 io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1610 io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1611 io.openx.in.search_attrs = 0;
1612 io.openx.in.file_attrs = 0;
1613 io.openx.in.write_time = 0;
1614 io.openx.in.size = 1024*1024;
1615 io.openx.in.timeout = 0;
1616 io.openx.in.fname = fname;
1618 io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1619 status = smb_raw_open(cli->tree, tctx, &io);
1620 CHECK_STATUS(status, NT_STATUS_OK);
1621 smbcli_close(cli->tree, io.openx.out.file.fnum);
1622 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1623 goto done;
1626 ret = true;
1628 done:
1629 smbcli_close(cli->tree, fnum);
1630 smbcli_unlink(cli->tree, fname);
1631 smbcli_deltree(cli->tree, BASEDIR);
1632 return ret;
1635 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1636 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1637 struct smbcli_state *cli)
1639 #define LONG_STREAM_SIZE 2
1640 char *lstream_name;
1641 const char *fname = BASEDIR "\\stream.txt";
1642 const char *fname_stream;
1643 NTSTATUS status;
1644 bool ret = true;
1645 int i;
1646 union smb_fileinfo finfo;
1648 if (!torture_setup_dir(cli, BASEDIR)) {
1649 return false;
1652 lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1654 for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1655 lstream_name[i] = (char)('a' + i%26);
1657 lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1659 torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1660 for (i = 0; i < 10000; i++) {
1661 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1662 lstream_name, i);
1663 ret = create_file_with_stream(tctx, cli, fname_stream);
1664 if (!ret) {
1665 goto done;
1669 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1670 finfo.generic.in.file.path = fname;
1672 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1673 CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1675 done:
1676 smbcli_unlink(cli->tree, fname);
1677 smbcli_deltree(cli->tree, BASEDIR);
1678 return ret;
1681 /* Test the effect of setting attributes on a stream. */
1682 static bool test_stream_attributes(struct torture_context *tctx,
1683 struct smbcli_state *cli)
1685 bool ret = true;
1686 NTSTATUS status;
1687 union smb_open io;
1688 const char *fname = BASEDIR "\\stream_attr.txt";
1689 const char *stream = "Stream One:$DATA";
1690 const char *fname_stream;
1691 int fnum = -1;
1692 union smb_fileinfo finfo;
1693 union smb_setfileinfo sfinfo;
1694 time_t basetime = (time(NULL) - 86400) & ~1;
1696 if (!torture_setup_dir(cli, BASEDIR)) {
1697 return false;
1700 torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1702 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1704 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1705 ret = create_file_with_stream(tctx, cli, fname_stream);
1706 if (!ret) {
1707 goto done;
1710 ZERO_STRUCT(finfo);
1711 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1712 finfo.generic.in.file.path = fname;
1713 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1714 CHECK_STATUS(status, NT_STATUS_OK);
1716 if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1717 printf("(%s) Incorrect attrib %x - should be %x\n", \
1718 __location__, (unsigned int)finfo.basic_info.out.attrib,
1719 (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1720 ret = false;
1721 goto done;
1724 /* Now open the stream name. */
1726 io.generic.level = RAW_OPEN_NTCREATEX;
1727 io.ntcreatex.in.root_fid.fnum = 0;
1728 io.ntcreatex.in.flags = 0;
1729 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1730 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1731 io.ntcreatex.in.create_options = 0;
1732 io.ntcreatex.in.file_attr = 0;
1733 io.ntcreatex.in.share_access = 0;
1734 io.ntcreatex.in.alloc_size = 0;
1735 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1736 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1737 io.ntcreatex.in.security_flags = 0;
1738 io.ntcreatex.in.fname = fname_stream;
1740 status = smb_raw_open(cli->tree, tctx, &io);
1741 CHECK_STATUS(status, NT_STATUS_OK);
1743 fnum = io.ntcreatex.out.file.fnum;
1745 /* Change the attributes + time on the stream fnum. */
1746 ZERO_STRUCT(sfinfo);
1747 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1748 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1750 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1751 sfinfo.generic.in.file.fnum = fnum;
1752 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1753 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1754 printf("(%s) %s - %s (should be %s)\n", __location__, "SETATTR",
1755 nt_errstr(status), nt_errstr(NT_STATUS_OK));
1756 ret = false;
1757 goto done;
1760 smbcli_close(cli->tree, fnum);
1761 fnum = -1;
1763 ZERO_STRUCT(finfo);
1764 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1765 finfo.generic.in.file.path = fname;
1766 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1767 if (!NT_STATUS_IS_OK(status)) {
1768 printf("(%s) %s pathinfo - %s\n", __location__, "SETATTRE", nt_errstr(status));
1769 ret = false;
1770 goto done;
1773 if (finfo.all_info.out.attrib != FILE_ATTRIBUTE_READONLY) {
1774 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1775 __location__,
1776 (unsigned int)finfo.all_info.out.attrib,
1777 (unsigned int)FILE_ATTRIBUTE_READONLY);
1778 ret = false;
1779 goto done;
1782 if (nt_time_to_unix(finfo.all_info.out.write_time) != basetime) {
1783 printf("(%s) time incorrect.\n",
1784 __location__);
1785 ret = false;
1786 goto done;
1789 done:
1791 if (fnum != -1) {
1792 smbcli_close(cli->tree, fnum);
1794 smbcli_unlink(cli->tree, fname);
1795 smbcli_deltree(cli->tree, BASEDIR);
1796 return ret;
1800 * A rough approximation of how a windows client creates the streams for use
1801 * in the summary tab.
1803 static bool test_stream_summary_tab(struct torture_context *tctx,
1804 struct smbcli_state *cli)
1806 bool ret = true;
1807 NTSTATUS status;
1808 union smb_open io;
1809 const char *fname = BASEDIR "\\stream_summary.txt";
1810 const char *stream = ":\005SummaryInformation:$DATA";
1811 const char *fname_stream = NULL;
1812 const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1813 const char *fname_tmp_stream = NULL;
1814 int fnum = -1;
1815 union smb_fileinfo finfo;
1816 union smb_rename rio;
1817 ssize_t retsize;
1819 if (!torture_setup_dir(cli, BASEDIR)) {
1820 return false;
1823 fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1824 fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1825 tmp_stream);
1827 /* Create summary info stream */
1828 ret = create_file_with_stream(tctx, cli, fname_stream);
1829 if (!ret) {
1830 goto done;
1833 /* Create summary info tmp update stream */
1834 ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1835 if (!ret) {
1836 goto done;
1839 /* Open tmp stream and write to it */
1840 io.generic.level = RAW_OPEN_NTCREATEX;
1841 io.ntcreatex.in.root_fid.fnum = 0;
1842 io.ntcreatex.in.flags = 0;
1843 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1844 io.ntcreatex.in.create_options = 0;
1845 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1846 io.ntcreatex.in.share_access = 0;
1847 io.ntcreatex.in.alloc_size = 0;
1848 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1849 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1850 io.ntcreatex.in.security_flags = 0;
1851 io.ntcreatex.in.fname = fname_tmp_stream;
1853 status = smb_raw_open(cli->tree, tctx, &io);
1854 CHECK_STATUS(status, NT_STATUS_OK);
1855 fnum = io.ntcreatex.out.file.fnum;
1857 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1858 CHECK_VALUE(retsize, 9);
1860 /* close the tmp stream. */
1861 smbcli_close(cli->tree, fnum);
1862 fnum = -1;
1864 /* Delete the current stream */
1865 smbcli_unlink(cli->tree, fname_stream);
1867 /* Do the rename. */
1868 rio.generic.level = RAW_RENAME_RENAME;
1869 rio.rename.in.pattern1 = fname_tmp_stream;
1870 rio.rename.in.pattern2 = stream;
1871 rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1872 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1873 status = smb_raw_rename(cli->tree, &rio);
1874 CHECK_STATUS(status, NT_STATUS_OK);
1876 /* Try to open the tmp stream that we just renamed away. */
1877 status = smb_raw_open(cli->tree, tctx, &io);
1878 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1880 /* Query the base file to make sure it's still there. */
1881 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1882 finfo.generic.in.file.path = fname;
1884 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1885 CHECK_STATUS(status, NT_STATUS_OK);
1887 done:
1889 if (fnum != -1) {
1890 smbcli_close(cli->tree, fnum);
1892 smbcli_unlink(cli->tree, fname);
1894 smbcli_deltree(cli->tree, BASEDIR);
1895 return ret;
1899 basic testing of streams calls
1901 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
1903 struct torture_suite *suite = torture_suite_create(tctx, "STREAMS");
1905 torture_suite_add_1smb_test(suite, "DIR", test_stream_dir);
1906 torture_suite_add_1smb_test(suite, "IO", test_stream_io);
1907 torture_suite_add_1smb_test(suite, "SHAREMODES",
1908 test_stream_sharemodes);
1909 torture_suite_add_1smb_test(suite, "DELETE", test_stream_delete);
1910 torture_suite_add_1smb_test(suite, "NAMES", test_stream_names);
1911 torture_suite_add_1smb_test(suite, "NAMES2", test_stream_names2);
1912 torture_suite_add_1smb_test(suite, "RENAME", test_stream_rename);
1913 torture_suite_add_1smb_test(suite, "RENAME2", test_stream_rename2);
1914 torture_suite_add_1smb_test(suite, "RENAME3", test_stream_rename3);
1915 torture_suite_add_1smb_test(suite, "CREATEDISP",
1916 test_stream_create_disposition);
1917 torture_suite_add_1smb_test(suite, "ATTR", test_stream_attributes);
1918 torture_suite_add_1smb_test(suite, "SUMTAB", test_stream_summary_tab);
1920 /* torture_suite_add_1smb_test(suite, "LARGESTREAMINFO", */
1921 /* test_stream_large_streaminfo); */
1923 return suite;