docs-xml: vfs_gpfs: fix typo
[Samba/bb.git] / source4 / torture / raw / streams.c
blobd48c555d22f3b8f662778786e8b696fb82059f61
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"
29 #include "lib/util/tsort.h"
30 #include "torture/raw/proto.h"
32 #define BASEDIR "\\teststreams"
34 #define CHECK_STATUS(status, correct) \
35 torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
37 #define CHECK_VALUE(v, correct) \
38 torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
40 #define CHECK_NTTIME(v, correct) \
41 torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
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)
62 check that a stream has the right contents
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)
69 int fnum;
70 const char *full_name;
71 uint8_t *buf;
72 ssize_t ret;
74 full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
76 fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
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;
84 return true;
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;
93 buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
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;
102 if (memcmp(buf, value, strlen(value)) != 0) {
103 printf("(%s) Bad data in stream\n", location);
104 return false;
107 smbcli_close(cli->tree, fnum);
108 return true;
111 static int qsort_string(char * const *s1, char * const *s2)
113 return strcmp(*s1, *s2);
116 static int qsort_stream(const struct stream_struct *s1, const struct stream_struct *s2)
118 return strcmp(s1->stream_name.s, s2->stream_name.s);
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)
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;
134 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
135 finfo.generic.in.file.path = fname;
137 status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
138 CHECK_STATUS(status, NT_STATUS_OK);
140 CHECK_VALUE(finfo.stream_info.out.num_streams, num_exp);
142 if (num_exp == 0) {
143 ret = true;
144 goto done;
147 exp_sort = (char **)talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
149 if (exp_sort == NULL) {
150 goto done;
153 TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
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));
160 if (stream_sort == NULL) {
161 goto done;
164 TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
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;
173 ret = true;
174 done:
175 talloc_free(tmp_ctx);
176 return ret;
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);
183 CHECK_STR(stream_sort[fail].stream_name.s, exp_sort[fail]);
184 talloc_free(tmp_ctx);
185 return ret;
189 test bahavior of streams on directories
191 static bool test_stream_dir(struct torture_context *tctx,
192 struct smbcli_state *cli)
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;
201 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
203 basedir_data = talloc_asprintf(tctx, "%s::$DATA", BASEDIR);
204 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
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);
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);
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);
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;
262 test basic behavior of streams on directories
264 static bool test_stream_io(struct torture_context *tctx,
265 struct smbcli_state *cli)
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;
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" };
280 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
282 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
283 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
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;
302 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", NULL);
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);
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);
315 smbcli_close(cli->tree, fnum);
317 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test data");
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;
325 printf("(%s) modifying stream\n", __location__);
326 retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
327 CHECK_VALUE(retsize, 10);
329 smbcli_close(cli->tree, fnum);
331 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$FOO", NULL);
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;
340 printf("(%s) modifying stream\n", __location__);
341 retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
342 CHECK_VALUE(retsize, 13);
344 smbcli_close(cli->tree, fnum);
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);
356 check_stream_list(tctx, cli, fname, 3, three);
358 printf("(%s) deleting stream\n", __location__);
359 status = smbcli_unlink(cli->tree, sname1);
360 CHECK_STATUS(status, NT_STATUS_OK);
362 check_stream_list(tctx, cli, fname, 2, two);
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;
371 status = smb_raw_open(cli->tree, tctx, &io);
372 CHECK_STATUS(status, NT_STATUS_OK);
373 fnum = io.ntcreatex.out.file.fnum;
375 smbcli_close(cli->tree, fnum);
376 status = smbcli_unlink(cli->tree, sname2);
377 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
379 check_stream_list(tctx, cli, fname, 1, one);
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);
391 printf("(%s) deleting file\n", __location__);
392 status = smbcli_unlink(cli->tree, fname);
393 CHECK_STATUS(status, NT_STATUS_OK);
395 done:
396 smbcli_close(cli->tree, fnum);
397 smbcli_deltree(cli->tree, BASEDIR);
398 return ret;
402 test stream sharemodes
404 static bool test_stream_sharemodes(struct torture_context *tctx,
405 struct smbcli_state *cli)
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;
415 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
417 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
418 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
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;
434 status = smb_raw_open(cli->tree, tctx, &io);
435 CHECK_STATUS(status, NT_STATUS_OK);
436 fnum1 = io.ntcreatex.out.file.fnum;
439 * A different stream does not give a sharing violation
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;
448 * ... whereas the same stream does with unchanged access/share_access
449 * flags
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);
457 io.ntcreatex.in.fname = sname2;
458 status = smb_raw_open(cli->tree, tctx, &io);
459 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
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;
470 * Test FILE_SHARE_DELETE on streams
472 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
473 * with SEC_STD_DELETE.
475 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
476 * be opened with SEC_STD_DELETE.
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 ending.
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.
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.
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.
495 static bool test_stream_delete(struct torture_context *tctx,
496 struct smbcli_state *cli)
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;
508 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
510 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
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;
526 status = smb_raw_open(cli->tree, tctx, &io);
527 CHECK_STATUS(status, NT_STATUS_OK);
528 fnum = io.ntcreatex.out.file.fnum;
530 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
531 CHECK_VALUE(retsize, 9);
534 * One stream opened without FILE_SHARE_DELETE prevents the main file
535 * to be deleted or even opened with DELETE access
538 status = smbcli_unlink(cli->tree, fname);
539 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
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);
547 smbcli_close(cli->tree, fnum);
550 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
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;
560 status = smbcli_unlink(cli->tree, fname);
561 CHECK_STATUS(status, NT_STATUS_OK);
564 * file access still works on the stream while the main file is closed
567 retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
568 CHECK_VALUE(retsize, 9);
570 finfo.generic.level = RAW_FILEINFO_STANDARD;
571 finfo.generic.in.file.path = fname;
574 * name-based access to both the main file and the stream does not
575 * work anymore but gives DELETE_PENDING
578 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
579 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
582 * older S3 doesn't do this
584 finfo.generic.in.file.path = sname1;
585 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
586 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
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
594 finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
595 finfo.all_info.in.file.fnum = fnum;
597 status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
598 CHECK_STATUS(status, NT_STATUS_OK);
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);
608 smbcli_close(cli->tree, fnum);
611 * After closing the stream the file is really gone.
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);
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;
626 finfo.generic.in.file.path = fname;
627 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
628 CHECK_STATUS(status, NT_STATUS_OK);
630 smbcli_close(cli->tree, fnum);
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;
642 test stream names
644 static bool test_stream_names(struct torture_context *tctx,
645 struct smbcli_state *cli)
647 NTSTATUS status;
648 union smb_open io;
649 union smb_fileinfo finfo;
650 union smb_fileinfo stinfo;
651 union smb_setfileinfo sinfo;
652 const char *fname = BASEDIR "\\stream_names.txt";
653 const char *sname1, *sname1b, *sname1c, *sname1d;
654 const char *sname2, *snamew, *snamew2;
655 const char *snamer1, *snamer2;
656 bool ret = true;
657 int fnum1 = -1;
658 int fnum2 = -1;
659 int fnum3 = -1;
660 int i;
661 const char *four[4] = {
662 "::$DATA",
663 ":\x05Stream\n One:$DATA",
664 ":MStream Two:$DATA",
665 ":?Stream*:$DATA"
667 const char *five1[5] = {
668 "::$DATA",
669 ":\x05Stream\n One:$DATA",
670 ":BeforeRename:$DATA",
671 ":MStream Two:$DATA",
672 ":?Stream*:$DATA"
674 const char *five2[5] = {
675 "::$DATA",
676 ":\x05Stream\n One:$DATA",
677 ":AfterRename:$DATA",
678 ":MStream Two:$DATA",
679 ":?Stream*:$DATA"
682 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
684 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
685 sname1b = talloc_asprintf(tctx, "%s:", sname1);
686 sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
687 sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
688 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
689 snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
690 snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
691 snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
692 snamer2 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "AfterRename");
694 printf("(%s) testing stream names\n", __location__);
695 io.generic.level = RAW_OPEN_NTCREATEX;
696 io.ntcreatex.in.root_fid.fnum = 0;
697 io.ntcreatex.in.flags = 0;
698 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
699 io.ntcreatex.in.create_options = 0;
700 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
701 io.ntcreatex.in.share_access = 0;
702 io.ntcreatex.in.alloc_size = 0;
703 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
704 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
705 io.ntcreatex.in.security_flags = 0;
706 io.ntcreatex.in.fname = fname;
708 status = smb_raw_open(cli->tree, tctx, &io);
709 CHECK_STATUS(status, NT_STATUS_OK);
710 fnum1 = io.ntcreatex.out.file.fnum;
713 * Make sure the create time of the streams are different from the
714 * base file.
716 sleep(2);
717 smbcli_close(cli->tree, fnum1);
719 io.generic.level = RAW_OPEN_NTCREATEX;
720 io.ntcreatex.in.root_fid.fnum = 0;
721 io.ntcreatex.in.flags = 0;
722 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
723 io.ntcreatex.in.create_options = 0;
724 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
725 io.ntcreatex.in.share_access = 0;
726 io.ntcreatex.in.alloc_size = 0;
727 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
728 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
729 io.ntcreatex.in.security_flags = 0;
730 io.ntcreatex.in.fname = sname1;
732 status = smb_raw_open(cli->tree, tctx, &io);
733 CHECK_STATUS(status, NT_STATUS_OK);
734 fnum1 = io.ntcreatex.out.file.fnum;
737 * A different stream does not give a sharing violation
740 io.ntcreatex.in.fname = sname2;
741 status = smb_raw_open(cli->tree, tctx, &io);
742 CHECK_STATUS(status, NT_STATUS_OK);
743 fnum2 = io.ntcreatex.out.file.fnum;
746 * ... whereas the same stream does with unchanged access/share_access
747 * flags
750 io.ntcreatex.in.fname = sname1;
751 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
752 status = smb_raw_open(cli->tree, tctx, &io);
753 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
755 io.ntcreatex.in.fname = sname1b;
756 status = smb_raw_open(cli->tree, tctx, &io);
757 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
759 io.ntcreatex.in.fname = sname1c;
760 status = smb_raw_open(cli->tree, tctx, &io);
761 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
762 /* w2k returns INVALID_PARAMETER */
763 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
764 } else {
765 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
768 io.ntcreatex.in.fname = sname1d;
769 status = smb_raw_open(cli->tree, tctx, &io);
770 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
771 /* w2k returns INVALID_PARAMETER */
772 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
773 } else {
774 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
777 io.ntcreatex.in.fname = sname2;
778 status = smb_raw_open(cli->tree, tctx, &io);
779 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
781 io.ntcreatex.in.fname = snamew;
782 status = smb_raw_open(cli->tree, tctx, &io);
783 CHECK_STATUS(status, NT_STATUS_OK);
784 fnum3 = io.ntcreatex.out.file.fnum;
786 io.ntcreatex.in.fname = snamew2;
787 status = smb_raw_open(cli->tree, tctx, &io);
788 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
790 ret &= check_stream_list(tctx, cli, fname, 4, four);
792 smbcli_close(cli->tree, fnum1);
793 smbcli_close(cli->tree, fnum2);
794 smbcli_close(cli->tree, fnum3);
796 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
797 finfo.generic.in.file.path = fname;
798 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
799 CHECK_STATUS(status, NT_STATUS_OK);
801 ret &= check_stream_list(tctx, cli, fname, 4, four);
803 for (i=0; i < 4; i++) {
804 NTTIME write_time;
805 uint64_t stream_size;
806 char *path = talloc_asprintf(tctx, "%s%s",
807 fname, four[i]);
809 char *rpath = talloc_strdup(path, path);
810 char *p = strrchr(rpath, ':');
811 /* eat :$DATA */
812 *p = 0;
813 p--;
814 if (*p == ':') {
815 /* eat ::$DATA */
816 *p = 0;
818 printf("(%s): i[%u][%s]\n", __location__, i, path);
819 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
820 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
821 SEC_FILE_WRITE_ATTRIBUTE |
822 SEC_RIGHTS_FILE_ALL;
823 io.ntcreatex.in.fname = path;
824 status = smb_raw_open(cli->tree, tctx, &io);
825 CHECK_STATUS(status, NT_STATUS_OK);
826 fnum1 = io.ntcreatex.out.file.fnum;
828 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
829 finfo.generic.in.file.path = fname;
830 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
831 CHECK_STATUS(status, NT_STATUS_OK);
833 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
834 stinfo.generic.in.file.fnum = fnum1;
835 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
836 CHECK_STATUS(status, NT_STATUS_OK);
837 if (!torture_setting_bool(tctx, "samba3", false)) {
838 CHECK_NTTIME(stinfo.all_info.out.create_time,
839 finfo.all_info.out.create_time);
840 CHECK_NTTIME(stinfo.all_info.out.access_time,
841 finfo.all_info.out.access_time);
842 CHECK_NTTIME(stinfo.all_info.out.write_time,
843 finfo.all_info.out.write_time);
844 CHECK_NTTIME(stinfo.all_info.out.change_time,
845 finfo.all_info.out.change_time);
847 CHECK_VALUE(stinfo.all_info.out.attrib,
848 finfo.all_info.out.attrib);
849 CHECK_VALUE(stinfo.all_info.out.size,
850 finfo.all_info.out.size);
851 CHECK_VALUE(stinfo.all_info.out.delete_pending,
852 finfo.all_info.out.delete_pending);
853 CHECK_VALUE(stinfo.all_info.out.directory,
854 finfo.all_info.out.directory);
855 CHECK_VALUE(stinfo.all_info.out.ea_size,
856 finfo.all_info.out.ea_size);
858 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
859 stinfo.generic.in.file.fnum = fnum1;
860 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
861 CHECK_STATUS(status, NT_STATUS_OK);
862 if (!torture_setting_bool(tctx, "samba3", false)) {
863 CHECK_STR(stinfo.name_info.out.fname.s, rpath);
866 write_time = finfo.all_info.out.write_time;
867 write_time += i*1000000;
868 write_time /= 1000000;
869 write_time *= 1000000;
871 ZERO_STRUCT(sinfo);
872 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
873 sinfo.basic_info.in.file.fnum = fnum1;
874 sinfo.basic_info.in.write_time = write_time;
875 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
876 status = smb_raw_setfileinfo(cli->tree, &sinfo);
877 CHECK_STATUS(status, NT_STATUS_OK);
879 stream_size = i*8192;
881 ZERO_STRUCT(sinfo);
882 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
883 sinfo.end_of_file_info.in.file.fnum = fnum1;
884 sinfo.end_of_file_info.in.size = stream_size;
885 status = smb_raw_setfileinfo(cli->tree, &sinfo);
886 CHECK_STATUS(status, NT_STATUS_OK);
888 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
889 stinfo.generic.in.file.fnum = fnum1;
890 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
891 CHECK_STATUS(status, NT_STATUS_OK);
892 if (!torture_setting_bool(tctx, "samba3", false)) {
893 CHECK_NTTIME(stinfo.all_info.out.write_time,
894 write_time);
895 CHECK_VALUE(stinfo.all_info.out.attrib,
896 finfo.all_info.out.attrib);
898 CHECK_VALUE(stinfo.all_info.out.size,
899 stream_size);
900 CHECK_VALUE(stinfo.all_info.out.delete_pending,
901 finfo.all_info.out.delete_pending);
902 CHECK_VALUE(stinfo.all_info.out.directory,
903 finfo.all_info.out.directory);
904 CHECK_VALUE(stinfo.all_info.out.ea_size,
905 finfo.all_info.out.ea_size);
907 ret &= check_stream_list(tctx, cli, fname, 4, four);
909 smbcli_close(cli->tree, fnum1);
910 talloc_free(path);
913 printf("(%s): testing stream renames\n", __location__);
914 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
915 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
916 SEC_FILE_WRITE_ATTRIBUTE |
917 SEC_RIGHTS_FILE_ALL;
918 io.ntcreatex.in.fname = snamer1;
919 status = smb_raw_open(cli->tree, tctx, &io);
920 CHECK_STATUS(status, NT_STATUS_OK);
921 fnum1 = io.ntcreatex.out.file.fnum;
923 ret &= check_stream_list(tctx, cli, fname, 5, five1);
925 ZERO_STRUCT(sinfo);
926 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
927 sinfo.rename_information.in.file.fnum = fnum1;
928 sinfo.rename_information.in.overwrite = true;
929 sinfo.rename_information.in.root_fid = 0;
930 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
931 status = smb_raw_setfileinfo(cli->tree, &sinfo);
932 CHECK_STATUS(status, NT_STATUS_OK);
934 ret &= check_stream_list(tctx, cli, fname, 5, five2);
936 ZERO_STRUCT(sinfo);
937 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
938 sinfo.rename_information.in.file.fnum = fnum1;
939 sinfo.rename_information.in.overwrite = false;
940 sinfo.rename_information.in.root_fid = 0;
941 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
942 status = smb_raw_setfileinfo(cli->tree, &sinfo);
943 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
945 ret &= check_stream_list(tctx, cli, fname, 5, five2);
947 ZERO_STRUCT(sinfo);
948 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
949 sinfo.rename_information.in.file.fnum = fnum1;
950 sinfo.rename_information.in.overwrite = true;
951 sinfo.rename_information.in.root_fid = 0;
952 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
953 status = smb_raw_setfileinfo(cli->tree, &sinfo);
954 if (torture_setting_bool(tctx, "samba4", false) ||
955 torture_setting_bool(tctx, "samba3", false)) {
956 /* why should this rename be considered invalid?? */
957 CHECK_STATUS(status, NT_STATUS_OK);
958 ret &= check_stream_list(tctx, cli, fname, 4, four);
959 } else {
960 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
961 ret &= check_stream_list(tctx, cli, fname, 5, five2);
965 /* TODO: we need to test more rename combinations */
967 done:
968 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
969 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
970 if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
971 status = smbcli_unlink(cli->tree, fname);
972 smbcli_deltree(cli->tree, BASEDIR);
973 return ret;
977 test stream names
979 static bool test_stream_names2(struct torture_context *tctx,
980 struct smbcli_state *cli)
982 NTSTATUS status;
983 union smb_open io;
984 const char *fname = BASEDIR "\\stream_names2.txt";
985 bool ret = true;
986 int fnum1 = -1;
987 uint8_t i;
989 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
991 printf("(%s) testing stream names\n", __location__);
992 io.generic.level = RAW_OPEN_NTCREATEX;
993 io.ntcreatex.in.root_fid.fnum = 0;
994 io.ntcreatex.in.flags = 0;
995 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
996 io.ntcreatex.in.create_options = 0;
997 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
998 io.ntcreatex.in.share_access = 0;
999 io.ntcreatex.in.alloc_size = 0;
1000 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1001 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1002 io.ntcreatex.in.security_flags = 0;
1003 io.ntcreatex.in.fname = fname;
1004 status = smb_raw_open(cli->tree, tctx, &io);
1005 CHECK_STATUS(status, NT_STATUS_OK);
1006 fnum1 = io.ntcreatex.out.file.fnum;
1008 for (i=0x01; i < 0x7F; i++) {
1009 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1010 fname, i, i);
1011 NTSTATUS expected;
1013 switch (i) {
1014 case '/':/*0x2F*/
1015 case ':':/*0x3A*/
1016 case '\\':/*0x5C*/
1017 expected = NT_STATUS_OBJECT_NAME_INVALID;
1018 break;
1019 default:
1020 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1021 break;
1025 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1026 io.ntcreatex.in.fname = path;
1027 status = smb_raw_open(cli->tree, tctx, &io);
1028 if (!NT_STATUS_EQUAL(status, expected)) {
1029 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1030 __location__, fname, isprint(i)?(char)i:' ', i,
1031 isprint(i)?"":" (not printable)",
1032 nt_errstr(expected));
1034 CHECK_STATUS(status, expected);
1036 talloc_free(path);
1039 done:
1040 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1041 status = smbcli_unlink(cli->tree, fname);
1042 smbcli_deltree(cli->tree, BASEDIR);
1043 return ret;
1046 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1047 check_fnum = true; \
1048 call_name = #call; \
1049 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1050 sfinfo.generic.in.file.fnum = fnum; \
1051 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1052 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1053 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1054 nt_errstr(status), nt_errstr(rightstatus)); \
1055 ret = false; \
1057 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1058 finfo1.generic.in.file.fnum = fnum; \
1059 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1060 if (!NT_STATUS_IS_OK(status2)) { \
1061 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1062 ret = false; \
1063 }} while (0)
1066 test stream renames
1068 static bool test_stream_rename(struct torture_context *tctx,
1069 struct smbcli_state *cli)
1071 NTSTATUS status, status2;
1072 union smb_open io;
1073 const char *fname = BASEDIR "\\stream_rename.txt";
1074 const char *sname1, *sname2;
1075 union smb_fileinfo finfo1;
1076 union smb_setfileinfo sfinfo;
1077 bool ret = true;
1078 int fnum = -1;
1079 bool check_fnum;
1080 const char *call_name;
1082 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1084 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1085 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1087 printf("(%s) testing stream renames\n", __location__);
1088 io.generic.level = RAW_OPEN_NTCREATEX;
1089 io.ntcreatex.in.root_fid.fnum = 0;
1090 io.ntcreatex.in.flags = 0;
1091 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1092 SEC_FILE_WRITE_ATTRIBUTE |
1093 SEC_RIGHTS_FILE_ALL;
1094 io.ntcreatex.in.create_options = 0;
1095 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1096 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1097 io.ntcreatex.in.alloc_size = 0;
1098 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1099 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1100 io.ntcreatex.in.security_flags = 0;
1101 io.ntcreatex.in.fname = sname1;
1103 /* Create two streams. */
1104 status = smb_raw_open(cli->tree, tctx, &io);
1105 CHECK_STATUS(status, NT_STATUS_OK);
1106 fnum = io.ntcreatex.out.file.fnum;
1107 if (fnum != -1) smbcli_close(cli->tree, fnum);
1109 io.ntcreatex.in.fname = sname2;
1110 status = smb_raw_open(cli->tree, tctx, &io);
1111 CHECK_STATUS(status, NT_STATUS_OK);
1112 fnum = io.ntcreatex.out.file.fnum;
1114 if (fnum != -1) smbcli_close(cli->tree, fnum);
1117 * Open the second stream.
1120 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1121 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1122 status = smb_raw_open(cli->tree, tctx, &io);
1123 CHECK_STATUS(status, NT_STATUS_OK);
1124 fnum = io.ntcreatex.out.file.fnum;
1127 * Now rename the second stream onto the first.
1130 ZERO_STRUCT(sfinfo);
1132 sfinfo.rename_information.in.overwrite = 1;
1133 sfinfo.rename_information.in.root_fid = 0;
1134 sfinfo.rename_information.in.new_name = ":Stream One";
1135 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1137 done:
1138 if (fnum != -1) smbcli_close(cli->tree, fnum);
1139 status = smbcli_unlink(cli->tree, fname);
1140 smbcli_deltree(cli->tree, BASEDIR);
1141 return ret;
1144 static bool test_stream_rename2(struct torture_context *tctx,
1145 struct smbcli_state *cli)
1147 NTSTATUS status;
1148 union smb_open io;
1149 const char *fname1 = BASEDIR "\\stream.txt";
1150 const char *fname2 = BASEDIR "\\stream2.txt";
1151 const char *stream_name1 = ":Stream One:$DATA";
1152 const char *stream_name2 = ":Stream Two:$DATA";
1153 const char *stream_name_default = "::$DATA";
1154 const char *sname1;
1155 const char *sname2;
1156 bool ret = true;
1157 int fnum = -1;
1158 union smb_setfileinfo sinfo;
1159 union smb_rename rio;
1161 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1163 sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1164 sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1166 io.generic.level = RAW_OPEN_NTCREATEX;
1167 io.ntcreatex.in.root_fid.fnum = 0;
1168 io.ntcreatex.in.flags = 0;
1169 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1170 SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1171 io.ntcreatex.in.create_options = 0;
1172 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1173 io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1174 NTCREATEX_SHARE_ACCESS_WRITE |
1175 NTCREATEX_SHARE_ACCESS_DELETE);
1176 io.ntcreatex.in.alloc_size = 0;
1177 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1178 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1179 io.ntcreatex.in.security_flags = 0;
1180 io.ntcreatex.in.fname = sname1;
1182 /* Open/create new stream. */
1183 status = smb_raw_open(cli->tree, tctx, &io);
1184 CHECK_STATUS(status, NT_STATUS_OK);
1186 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1189 * Check raw rename with <base>:<stream>.
1191 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1192 __location__);
1193 rio.generic.level = RAW_RENAME_NTRENAME;
1194 rio.ntrename.in.old_name = sname1;
1195 rio.ntrename.in.new_name = sname2;
1196 rio.ntrename.in.attrib = 0;
1197 rio.ntrename.in.cluster_size = 0;
1198 rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1199 status = smb_raw_rename(cli->tree, &rio);
1200 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1203 * Check raw rename to the default stream using :<stream>.
1205 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1206 __location__);
1207 rio.ntrename.in.new_name = stream_name_default;
1208 status = smb_raw_rename(cli->tree, &rio);
1209 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1212 * Check raw rename using :<stream>.
1214 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1215 __location__);
1216 rio.ntrename.in.new_name = stream_name2;
1217 status = smb_raw_rename(cli->tree, &rio);
1218 CHECK_STATUS(status, NT_STATUS_OK);
1221 * Check raw rename of a stream to a file.
1223 printf("(%s) Checking NTRENAME of a stream to a file\n",
1224 __location__);
1225 rio.ntrename.in.old_name = sname2;
1226 rio.ntrename.in.new_name = fname2;
1227 status = smb_raw_rename(cli->tree, &rio);
1228 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1231 * Check raw rename of a file to a stream.
1233 printf("(%s) Checking NTRENAME of a file to a stream\n",
1234 __location__);
1236 /* Create the file. */
1237 io.ntcreatex.in.fname = fname2;
1238 status = smb_raw_open(cli->tree, tctx, &io);
1239 CHECK_STATUS(status, NT_STATUS_OK);
1240 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1242 /* Try the rename. */
1243 rio.ntrename.in.old_name = fname2;
1244 rio.ntrename.in.new_name = sname1;
1245 status = smb_raw_rename(cli->tree, &rio);
1246 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1249 * Reopen the stream for trans2 renames.
1251 io.ntcreatex.in.fname = sname2;
1252 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1253 status = smb_raw_open(cli->tree, tctx, &io);
1254 CHECK_STATUS(status, NT_STATUS_OK);
1255 fnum = io.ntcreatex.out.file.fnum;
1258 * Check trans2 rename of a stream using :<stream>.
1260 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1261 __location__);
1262 ZERO_STRUCT(sinfo);
1263 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1264 sinfo.rename_information.in.file.fnum = fnum;
1265 sinfo.rename_information.in.overwrite = 1;
1266 sinfo.rename_information.in.root_fid = 0;
1267 sinfo.rename_information.in.new_name = stream_name1;
1268 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1269 CHECK_STATUS(status, NT_STATUS_OK);
1272 * Check trans2 rename of an overwriting stream using :<stream>.
1274 printf("(%s) Checking trans2 rename of an overwriting stream using "
1275 ":<stream>\n", __location__);
1277 /* Create second stream. */
1278 io.ntcreatex.in.fname = sname2;
1279 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1280 status = smb_raw_open(cli->tree, tctx, &io);
1281 CHECK_STATUS(status, NT_STATUS_OK);
1282 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1284 /* Rename the first stream onto the second. */
1285 sinfo.rename_information.in.file.fnum = fnum;
1286 sinfo.rename_information.in.new_name = stream_name2;
1287 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1288 CHECK_STATUS(status, NT_STATUS_OK);
1290 smbcli_close(cli->tree, fnum);
1293 * Reopen the stream with the new name.
1295 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1296 io.ntcreatex.in.fname = sname2;
1297 status = smb_raw_open(cli->tree, tctx, &io);
1298 CHECK_STATUS(status, NT_STATUS_OK);
1299 fnum = io.ntcreatex.out.file.fnum;
1302 * Check trans2 rename of a stream using <base>:<stream>.
1304 printf("(%s) Checking trans2 rename of a stream using "
1305 "<base>:<stream>\n", __location__);
1306 sinfo.rename_information.in.file.fnum = fnum;
1307 sinfo.rename_information.in.new_name = sname1;
1308 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1309 CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1312 * Samba3 doesn't currently support renaming a stream to the default
1313 * stream. This test does pass on windows.
1315 if (torture_setting_bool(tctx, "samba3", false) ||
1316 torture_setting_bool(tctx, "samba4", false)) {
1317 goto done;
1321 * Check trans2 rename to the default stream using :<stream>.
1323 printf("(%s) Checking trans2 rename to defaualt stream using "
1324 ":<stream>\n", __location__);
1325 sinfo.rename_information.in.file.fnum = fnum;
1326 sinfo.rename_information.in.new_name = stream_name_default;
1327 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1328 CHECK_STATUS(status, NT_STATUS_OK);
1330 smbcli_close(cli->tree, fnum);
1332 done:
1333 smbcli_close(cli->tree, fnum);
1334 status = smbcli_unlink(cli->tree, fname1);
1335 status = smbcli_unlink(cli->tree, fname2);
1336 smbcli_deltree(cli->tree, BASEDIR);
1337 return ret;
1341 test stream renames
1343 static bool test_stream_rename3(struct torture_context *tctx,
1344 struct smbcli_state *cli)
1346 NTSTATUS status, status2;
1347 union smb_open io;
1348 const char *fname = BASEDIR "\\stream_rename.txt";
1349 const char *sname1, *sname2;
1350 union smb_fileinfo finfo1;
1351 union smb_setfileinfo sfinfo;
1352 bool ret = true;
1353 int fnum = -1;
1354 int fnum2 = -1;
1355 bool check_fnum;
1356 const char *call_name;
1358 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1360 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1361 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1363 printf("(%s) testing stream renames\n", __location__);
1364 io.generic.level = RAW_OPEN_NTCREATEX;
1365 io.ntcreatex.in.root_fid.fnum = 0;
1366 io.ntcreatex.in.flags = 0;
1367 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1368 SEC_FILE_WRITE_ATTRIBUTE |
1369 SEC_RIGHTS_FILE_ALL;
1370 io.ntcreatex.in.create_options = 0;
1371 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1372 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1373 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1374 io.ntcreatex.in.alloc_size = 0;
1375 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1376 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1377 io.ntcreatex.in.security_flags = 0;
1378 io.ntcreatex.in.fname = sname1;
1380 /* Create two streams. */
1381 status = smb_raw_open(cli->tree, tctx, &io);
1382 CHECK_STATUS(status, NT_STATUS_OK);
1383 fnum = io.ntcreatex.out.file.fnum;
1384 if (fnum != -1) smbcli_close(cli->tree, fnum);
1386 io.ntcreatex.in.fname = sname2;
1387 status = smb_raw_open(cli->tree, tctx, &io);
1388 CHECK_STATUS(status, NT_STATUS_OK);
1389 fnum = io.ntcreatex.out.file.fnum;
1391 if (fnum != -1) smbcli_close(cli->tree, fnum);
1393 /* open the second stream. */
1394 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1395 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1396 status = smb_raw_open(cli->tree, tctx, &io);
1397 CHECK_STATUS(status, NT_STATUS_OK);
1398 fnum = io.ntcreatex.out.file.fnum;
1400 /* Keep a handle to the first stream open. */
1401 io.ntcreatex.in.fname = sname1;
1402 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1403 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1404 status = smb_raw_open(cli->tree, tctx, &io);
1405 CHECK_STATUS(status, NT_STATUS_OK);
1406 fnum2 = io.ntcreatex.out.file.fnum;
1408 ZERO_STRUCT(sfinfo);
1409 sfinfo.rename_information.in.overwrite = 1;
1410 sfinfo.rename_information.in.root_fid = 0;
1411 sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1412 if (torture_setting_bool(tctx, "samba4", false) ||
1413 torture_setting_bool(tctx, "samba3", false)) {
1414 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1415 } else {
1416 CHECK_CALL_FNUM(RENAME_INFORMATION,
1417 NT_STATUS_INVALID_PARAMETER);
1421 done:
1422 if (fnum != -1) smbcli_close(cli->tree, fnum);
1423 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1424 status = smbcli_unlink(cli->tree, fname);
1425 smbcli_deltree(cli->tree, BASEDIR);
1426 return ret;
1429 static bool create_file_with_stream(struct torture_context *tctx,
1430 struct smbcli_state *cli,
1431 const char *stream)
1433 NTSTATUS status;
1434 bool ret = true;
1435 union smb_open io;
1437 /* Create a file with a stream */
1438 io.generic.level = RAW_OPEN_NTCREATEX;
1439 io.ntcreatex.in.root_fid.fnum = 0;
1440 io.ntcreatex.in.flags = 0;
1441 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1442 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1443 io.ntcreatex.in.create_options = 0;
1444 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1445 io.ntcreatex.in.share_access = 0;
1446 io.ntcreatex.in.alloc_size = 0;
1447 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1448 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1449 io.ntcreatex.in.security_flags = 0;
1450 io.ntcreatex.in.fname = stream;
1452 status = smb_raw_open(cli->tree, tctx, &io);
1453 CHECK_STATUS(status, NT_STATUS_OK);
1455 done:
1456 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1457 return ret;
1460 /* Test how streams interact with create dispositions */
1461 static bool test_stream_create_disposition(struct torture_context *tctx,
1462 struct smbcli_state *cli)
1464 NTSTATUS status;
1465 union smb_open io;
1466 const char *fname = BASEDIR "\\stream.txt";
1467 const char *stream = "Stream One:$DATA";
1468 const char *fname_stream;
1469 const char *default_stream_name = "::$DATA";
1470 const char *stream_list[2];
1471 bool ret = false;
1472 int fnum = -1;
1474 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1476 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1478 stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1479 stream_list[1] = default_stream_name;
1481 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1482 goto done;
1485 /* Open the base file with OPEN */
1486 io.generic.level = RAW_OPEN_NTCREATEX;
1487 io.ntcreatex.in.root_fid.fnum = 0;
1488 io.ntcreatex.in.flags = 0;
1489 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1490 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1491 io.ntcreatex.in.create_options = 0;
1492 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1493 io.ntcreatex.in.share_access = 0;
1494 io.ntcreatex.in.alloc_size = 0;
1495 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1496 io.ntcreatex.in.security_flags = 0;
1497 io.ntcreatex.in.fname = fname;
1500 * check ntcreatex open: sanity check
1502 printf("(%s) Checking ntcreatex disp: open\n", __location__);
1503 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1504 status = smb_raw_open(cli->tree, tctx, &io);
1505 CHECK_STATUS(status, NT_STATUS_OK);
1506 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1507 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1508 goto done;
1512 * check ntcreatex overwrite
1514 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1515 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1516 status = smb_raw_open(cli->tree, tctx, &io);
1517 CHECK_STATUS(status, NT_STATUS_OK);
1518 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1519 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1520 goto done;
1524 * check ntcreatex overwrite_if
1526 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1527 smbcli_unlink(cli->tree, fname);
1528 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1529 goto done;
1532 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1533 status = smb_raw_open(cli->tree, tctx, &io);
1534 CHECK_STATUS(status, NT_STATUS_OK);
1535 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1536 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1537 goto done;
1541 * check ntcreatex supersede
1543 printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1544 smbcli_unlink(cli->tree, fname);
1545 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1546 goto done;
1549 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1550 status = smb_raw_open(cli->tree, tctx, &io);
1551 CHECK_STATUS(status, NT_STATUS_OK);
1552 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1553 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1554 goto done;
1558 * check ntcreatex overwrite_if on a stream.
1560 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1561 __location__);
1562 smbcli_unlink(cli->tree, fname);
1563 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1564 goto done;
1567 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1568 io.ntcreatex.in.fname = fname_stream;
1569 status = smb_raw_open(cli->tree, tctx, &io);
1570 CHECK_STATUS(status, NT_STATUS_OK);
1571 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1572 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1573 goto done;
1577 * check openx overwrite_if
1579 printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1580 smbcli_unlink(cli->tree, fname);
1581 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1582 goto done;
1585 io.openx.level = RAW_OPEN_OPENX;
1586 io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1587 io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1588 io.openx.in.search_attrs = 0;
1589 io.openx.in.file_attrs = 0;
1590 io.openx.in.write_time = 0;
1591 io.openx.in.size = 1024*1024;
1592 io.openx.in.timeout = 0;
1593 io.openx.in.fname = fname;
1595 io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1596 status = smb_raw_open(cli->tree, tctx, &io);
1597 CHECK_STATUS(status, NT_STATUS_OK);
1598 smbcli_close(cli->tree, io.openx.out.file.fnum);
1599 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1600 goto done;
1603 ret = true;
1605 done:
1606 smbcli_close(cli->tree, fnum);
1607 smbcli_unlink(cli->tree, fname);
1608 smbcli_deltree(cli->tree, BASEDIR);
1609 return ret;
1612 #if 0
1613 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1614 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1615 struct smbcli_state *cli)
1617 #define LONG_STREAM_SIZE 2
1618 char *lstream_name;
1619 const char *fname = BASEDIR "\\stream.txt";
1620 const char *fname_stream;
1621 NTSTATUS status;
1622 bool ret = true;
1623 int i;
1624 union smb_fileinfo finfo;
1626 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1628 lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1630 for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1631 lstream_name[i] = (char)('a' + i%26);
1633 lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1635 torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1636 for (i = 0; i < 10000; i++) {
1637 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1638 lstream_name, i);
1639 ret = create_file_with_stream(tctx, cli, fname_stream);
1640 if (!ret) {
1641 goto done;
1645 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1646 finfo.generic.in.file.path = fname;
1648 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1649 CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1651 done:
1652 smbcli_unlink(cli->tree, fname);
1653 smbcli_deltree(cli->tree, BASEDIR);
1654 return ret;
1656 #endif
1658 /* Test the effect of setting attributes on a stream. */
1659 static bool test_stream_attributes(struct torture_context *tctx,
1660 struct smbcli_state *cli)
1662 bool ret = true;
1663 NTSTATUS status;
1664 union smb_open io;
1665 const char *fname = BASEDIR "\\stream_attr.txt";
1666 const char *stream = "Stream One:$DATA";
1667 const char *fname_stream;
1668 int fnum = -1;
1669 union smb_fileinfo finfo;
1670 union smb_setfileinfo sfinfo;
1671 time_t basetime = (time(NULL) - 86400) & ~1;
1673 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1675 torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1677 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1679 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1680 ret = create_file_with_stream(tctx, cli, fname_stream);
1681 if (!ret) {
1682 goto done;
1685 ZERO_STRUCT(finfo);
1686 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1687 finfo.generic.in.file.path = fname;
1688 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1689 CHECK_STATUS(status, NT_STATUS_OK);
1691 if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1692 printf("(%s) Incorrect attrib %x - should be %x\n", \
1693 __location__, (unsigned int)finfo.basic_info.out.attrib,
1694 (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1695 ret = false;
1696 goto done;
1699 /* Now open the stream name. */
1701 io.generic.level = RAW_OPEN_NTCREATEX;
1702 io.ntcreatex.in.root_fid.fnum = 0;
1703 io.ntcreatex.in.flags = 0;
1704 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1705 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1706 io.ntcreatex.in.create_options = 0;
1707 io.ntcreatex.in.file_attr = 0;
1708 io.ntcreatex.in.share_access = 0;
1709 io.ntcreatex.in.alloc_size = 0;
1710 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1711 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1712 io.ntcreatex.in.security_flags = 0;
1713 io.ntcreatex.in.fname = fname_stream;
1715 status = smb_raw_open(cli->tree, tctx, &io);
1716 CHECK_STATUS(status, NT_STATUS_OK);
1718 fnum = io.ntcreatex.out.file.fnum;
1720 /* Change the attributes + time on the stream fnum. */
1721 ZERO_STRUCT(sfinfo);
1722 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1723 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1725 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1726 sfinfo.generic.in.file.fnum = fnum;
1727 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1728 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1729 printf("(%s) %s - %s (should be %s)\n", __location__, "SETATTR",
1730 nt_errstr(status), nt_errstr(NT_STATUS_OK));
1731 ret = false;
1732 goto done;
1735 smbcli_close(cli->tree, fnum);
1736 fnum = -1;
1738 ZERO_STRUCT(finfo);
1739 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1740 finfo.generic.in.file.path = fname;
1741 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1742 if (!NT_STATUS_IS_OK(status)) {
1743 printf("(%s) %s pathinfo - %s\n", __location__, "SETATTRE", nt_errstr(status));
1744 ret = false;
1745 goto done;
1748 if (finfo.all_info.out.attrib != FILE_ATTRIBUTE_READONLY) {
1749 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1750 __location__,
1751 (unsigned int)finfo.all_info.out.attrib,
1752 (unsigned int)FILE_ATTRIBUTE_READONLY);
1753 ret = false;
1754 goto done;
1757 if (nt_time_to_unix(finfo.all_info.out.write_time) != basetime) {
1758 printf("(%s) time incorrect.\n",
1759 __location__);
1760 ret = false;
1761 goto done;
1764 done:
1766 if (fnum != -1) {
1767 smbcli_close(cli->tree, fnum);
1769 smbcli_unlink(cli->tree, fname);
1770 smbcli_deltree(cli->tree, BASEDIR);
1771 return ret;
1775 * A rough approximation of how a windows client creates the streams for use
1776 * in the summary tab.
1778 static bool test_stream_summary_tab(struct torture_context *tctx,
1779 struct smbcli_state *cli)
1781 bool ret = true;
1782 NTSTATUS status;
1783 union smb_open io;
1784 const char *fname = BASEDIR "\\stream_summary.txt";
1785 const char *stream = ":\005SummaryInformation:$DATA";
1786 const char *fname_stream = NULL;
1787 const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1788 const char *fname_tmp_stream = NULL;
1789 int fnum = -1;
1790 union smb_fileinfo finfo;
1791 union smb_rename rio;
1792 ssize_t retsize;
1794 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1796 fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1797 fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1798 tmp_stream);
1800 /* Create summary info stream */
1801 ret = create_file_with_stream(tctx, cli, fname_stream);
1802 if (!ret) {
1803 goto done;
1806 /* Create summary info tmp update stream */
1807 ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1808 if (!ret) {
1809 goto done;
1812 /* Open tmp stream and write to it */
1813 io.generic.level = RAW_OPEN_NTCREATEX;
1814 io.ntcreatex.in.root_fid.fnum = 0;
1815 io.ntcreatex.in.flags = 0;
1816 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1817 io.ntcreatex.in.create_options = 0;
1818 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1819 io.ntcreatex.in.share_access = 0;
1820 io.ntcreatex.in.alloc_size = 0;
1821 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1822 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1823 io.ntcreatex.in.security_flags = 0;
1824 io.ntcreatex.in.fname = fname_tmp_stream;
1826 status = smb_raw_open(cli->tree, tctx, &io);
1827 CHECK_STATUS(status, NT_STATUS_OK);
1828 fnum = io.ntcreatex.out.file.fnum;
1830 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1831 CHECK_VALUE(retsize, 9);
1833 /* close the tmp stream. */
1834 smbcli_close(cli->tree, fnum);
1835 fnum = -1;
1837 /* Delete the current stream */
1838 smbcli_unlink(cli->tree, fname_stream);
1840 /* Do the rename. */
1841 rio.generic.level = RAW_RENAME_RENAME;
1842 rio.rename.in.pattern1 = fname_tmp_stream;
1843 rio.rename.in.pattern2 = stream;
1844 rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1845 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1846 status = smb_raw_rename(cli->tree, &rio);
1847 CHECK_STATUS(status, NT_STATUS_OK);
1849 /* Try to open the tmp stream that we just renamed away. */
1850 status = smb_raw_open(cli->tree, tctx, &io);
1851 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1853 /* Query the base file to make sure it's still there. */
1854 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1855 finfo.generic.in.file.path = fname;
1857 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1858 CHECK_STATUS(status, NT_STATUS_OK);
1860 done:
1862 if (fnum != -1) {
1863 smbcli_close(cli->tree, fnum);
1865 smbcli_unlink(cli->tree, fname);
1867 smbcli_deltree(cli->tree, BASEDIR);
1868 return ret;
1872 basic testing of streams calls
1874 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
1876 struct torture_suite *suite = torture_suite_create(tctx, "streams");
1878 torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
1879 torture_suite_add_1smb_test(suite, "io", test_stream_io);
1880 torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
1881 torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
1882 torture_suite_add_1smb_test(suite, "names", test_stream_names);
1883 torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
1884 torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
1885 torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
1886 torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
1887 torture_suite_add_1smb_test(suite, "createdisp",
1888 test_stream_create_disposition);
1889 torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
1890 torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
1892 #if 0
1893 torture_suite_add_1smb_test(suite, "LARGESTREAMINFO",
1894 test_stream_large_streaminfo);
1895 #endif
1897 return suite;