s4-torture: Show that we cannot have extended attributes on streams
[Samba/gebeck_regimport.git] / source4 / torture / raw / streams.c
blob593bbe2a942decc2e09f9b284d0b7986d62439cd
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_FLAG_MAXIMUM_ALLOWED;
699 io.ntcreatex.in.create_options = 0;
700 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
701 io.ntcreatex.in.share_access =
702 NTCREATEX_SHARE_ACCESS_READ |
703 NTCREATEX_SHARE_ACCESS_WRITE;
704 io.ntcreatex.in.alloc_size = 0;
705 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
706 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
707 io.ntcreatex.in.security_flags = 0;
708 io.ntcreatex.in.fname = fname;
710 status = smb_raw_open(cli->tree, tctx, &io);
711 CHECK_STATUS(status, NT_STATUS_OK);
712 fnum1 = io.ntcreatex.out.file.fnum;
714 torture_comment(tctx, "Adding two EAs to base file\n");
715 ZERO_STRUCT(sinfo);
716 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
717 sinfo.generic.in.file.fnum = fnum1;
718 sinfo.ea_set.in.num_eas = 2;
719 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
720 sinfo.ea_set.in.eas[0].flags = 0;
721 sinfo.ea_set.in.eas[0].name.s = "EAONE";
722 sinfo.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
723 sinfo.ea_set.in.eas[1].flags = 0;
724 sinfo.ea_set.in.eas[1].name.s = "SECONDEA";
725 sinfo.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
727 status = smb_raw_setfileinfo(cli->tree, &sinfo);
728 CHECK_STATUS(status, NT_STATUS_OK);
731 * Make sure the create time of the streams are different from the
732 * base file.
734 sleep(2);
735 smbcli_close(cli->tree, fnum1);
737 io.generic.level = RAW_OPEN_NTCREATEX;
738 io.ntcreatex.in.root_fid.fnum = 0;
739 io.ntcreatex.in.flags = 0;
740 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
741 io.ntcreatex.in.create_options = 0;
742 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
743 io.ntcreatex.in.share_access =
744 NTCREATEX_SHARE_ACCESS_READ |
745 NTCREATEX_SHARE_ACCESS_WRITE;
746 io.ntcreatex.in.alloc_size = 0;
747 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
748 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
749 io.ntcreatex.in.security_flags = 0;
750 io.ntcreatex.in.fname = sname1;
752 status = smb_raw_open(cli->tree, tctx, &io);
753 CHECK_STATUS(status, NT_STATUS_OK);
754 fnum1 = io.ntcreatex.out.file.fnum;
756 torture_comment(tctx, "Adding one EAs to first stream file\n");
757 ZERO_STRUCT(sinfo);
758 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
759 sinfo.generic.in.file.fnum = fnum1;
760 sinfo.ea_set.in.num_eas = 1;
761 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 1);
762 sinfo.ea_set.in.eas[0].flags = 0;
763 sinfo.ea_set.in.eas[0].name.s = "STREAMEA";
764 sinfo.ea_set.in.eas[0].value = data_blob_string_const("EA_VALUE1");
766 status = smb_raw_setfileinfo(cli->tree, &sinfo);
767 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
770 * A different stream does not give a sharing violation
773 io.ntcreatex.in.fname = sname2;
774 status = smb_raw_open(cli->tree, tctx, &io);
775 CHECK_STATUS(status, NT_STATUS_OK);
776 fnum2 = io.ntcreatex.out.file.fnum;
779 * ... whereas the same stream does with unchanged access/share_access
780 * flags
783 io.ntcreatex.in.fname = sname1;
784 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
785 status = smb_raw_open(cli->tree, tctx, &io);
786 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
788 io.ntcreatex.in.fname = sname1b;
789 status = smb_raw_open(cli->tree, tctx, &io);
790 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
792 io.ntcreatex.in.fname = sname1c;
793 status = smb_raw_open(cli->tree, tctx, &io);
794 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
795 /* w2k returns INVALID_PARAMETER */
796 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
797 } else {
798 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
801 io.ntcreatex.in.fname = sname1d;
802 status = smb_raw_open(cli->tree, tctx, &io);
803 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
804 /* w2k returns INVALID_PARAMETER */
805 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
806 } else {
807 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
810 io.ntcreatex.in.fname = sname2;
811 status = smb_raw_open(cli->tree, tctx, &io);
812 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
814 io.ntcreatex.in.fname = snamew;
815 status = smb_raw_open(cli->tree, tctx, &io);
816 CHECK_STATUS(status, NT_STATUS_OK);
817 fnum3 = io.ntcreatex.out.file.fnum;
819 io.ntcreatex.in.fname = snamew2;
820 status = smb_raw_open(cli->tree, tctx, &io);
821 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
823 ret &= check_stream_list(tctx, cli, fname, 4, four);
825 smbcli_close(cli->tree, fnum1);
826 smbcli_close(cli->tree, fnum2);
827 smbcli_close(cli->tree, fnum3);
829 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
830 finfo.generic.in.file.path = fname;
831 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
832 CHECK_STATUS(status, NT_STATUS_OK);
834 ret &= check_stream_list(tctx, cli, fname, 4, four);
836 for (i=0; i < 4; i++) {
837 NTTIME write_time;
838 uint64_t stream_size;
839 char *path = talloc_asprintf(tctx, "%s%s",
840 fname, four[i]);
842 char *rpath = talloc_strdup(path, path);
843 char *p = strrchr(rpath, ':');
844 /* eat :$DATA */
845 *p = 0;
846 p--;
847 if (*p == ':') {
848 /* eat ::$DATA */
849 *p = 0;
851 printf("(%s): i[%u][%s]\n", __location__, i, path);
852 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
853 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
854 SEC_FILE_WRITE_ATTRIBUTE |
855 SEC_RIGHTS_FILE_ALL;
856 io.ntcreatex.in.fname = path;
857 status = smb_raw_open(cli->tree, tctx, &io);
858 CHECK_STATUS(status, NT_STATUS_OK);
859 fnum1 = io.ntcreatex.out.file.fnum;
861 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
862 finfo.generic.in.file.path = fname;
863 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
864 CHECK_STATUS(status, NT_STATUS_OK);
866 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
867 stinfo.generic.in.file.fnum = fnum1;
868 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
869 CHECK_STATUS(status, NT_STATUS_OK);
870 if (!torture_setting_bool(tctx, "samba3", false)) {
871 CHECK_NTTIME(stinfo.all_info.out.create_time,
872 finfo.all_info.out.create_time);
873 CHECK_NTTIME(stinfo.all_info.out.access_time,
874 finfo.all_info.out.access_time);
875 CHECK_NTTIME(stinfo.all_info.out.write_time,
876 finfo.all_info.out.write_time);
877 CHECK_NTTIME(stinfo.all_info.out.change_time,
878 finfo.all_info.out.change_time);
880 CHECK_VALUE(stinfo.all_info.out.attrib,
881 finfo.all_info.out.attrib);
882 CHECK_VALUE(stinfo.all_info.out.size,
883 finfo.all_info.out.size);
884 CHECK_VALUE(stinfo.all_info.out.delete_pending,
885 finfo.all_info.out.delete_pending);
886 CHECK_VALUE(stinfo.all_info.out.directory,
887 finfo.all_info.out.directory);
888 CHECK_VALUE(stinfo.all_info.out.ea_size,
889 finfo.all_info.out.ea_size);
891 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
892 stinfo.generic.in.file.fnum = fnum1;
893 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
894 CHECK_STATUS(status, NT_STATUS_OK);
895 if (!torture_setting_bool(tctx, "samba3", false)) {
896 CHECK_STR(stinfo.name_info.out.fname.s, rpath);
899 write_time = finfo.all_info.out.write_time;
900 write_time += i*1000000;
901 write_time /= 1000000;
902 write_time *= 1000000;
904 ZERO_STRUCT(sinfo);
905 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
906 sinfo.basic_info.in.file.fnum = fnum1;
907 sinfo.basic_info.in.write_time = write_time;
908 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
909 status = smb_raw_setfileinfo(cli->tree, &sinfo);
910 CHECK_STATUS(status, NT_STATUS_OK);
912 stream_size = i*8192;
914 ZERO_STRUCT(sinfo);
915 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
916 sinfo.end_of_file_info.in.file.fnum = fnum1;
917 sinfo.end_of_file_info.in.size = stream_size;
918 status = smb_raw_setfileinfo(cli->tree, &sinfo);
919 CHECK_STATUS(status, NT_STATUS_OK);
921 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
922 stinfo.generic.in.file.fnum = fnum1;
923 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
924 CHECK_STATUS(status, NT_STATUS_OK);
925 if (!torture_setting_bool(tctx, "samba3", false)) {
926 CHECK_NTTIME(stinfo.all_info.out.write_time,
927 write_time);
928 CHECK_VALUE(stinfo.all_info.out.attrib,
929 finfo.all_info.out.attrib);
931 CHECK_VALUE(stinfo.all_info.out.size,
932 stream_size);
933 CHECK_VALUE(stinfo.all_info.out.delete_pending,
934 finfo.all_info.out.delete_pending);
935 CHECK_VALUE(stinfo.all_info.out.directory,
936 finfo.all_info.out.directory);
937 CHECK_VALUE(stinfo.all_info.out.ea_size,
938 finfo.all_info.out.ea_size);
940 ret &= check_stream_list(tctx, cli, fname, 4, four);
942 smbcli_close(cli->tree, fnum1);
943 talloc_free(path);
946 printf("(%s): testing stream renames\n", __location__);
947 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
948 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
949 SEC_FILE_WRITE_ATTRIBUTE |
950 SEC_RIGHTS_FILE_ALL;
951 io.ntcreatex.in.fname = snamer1;
952 status = smb_raw_open(cli->tree, tctx, &io);
953 CHECK_STATUS(status, NT_STATUS_OK);
954 fnum1 = io.ntcreatex.out.file.fnum;
956 ret &= check_stream_list(tctx, cli, fname, 5, five1);
958 ZERO_STRUCT(sinfo);
959 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
960 sinfo.rename_information.in.file.fnum = fnum1;
961 sinfo.rename_information.in.overwrite = true;
962 sinfo.rename_information.in.root_fid = 0;
963 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
964 status = smb_raw_setfileinfo(cli->tree, &sinfo);
965 CHECK_STATUS(status, NT_STATUS_OK);
967 ret &= check_stream_list(tctx, cli, fname, 5, five2);
969 ZERO_STRUCT(sinfo);
970 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
971 sinfo.rename_information.in.file.fnum = fnum1;
972 sinfo.rename_information.in.overwrite = false;
973 sinfo.rename_information.in.root_fid = 0;
974 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
975 status = smb_raw_setfileinfo(cli->tree, &sinfo);
976 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
978 ret &= check_stream_list(tctx, cli, fname, 5, five2);
980 ZERO_STRUCT(sinfo);
981 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
982 sinfo.rename_information.in.file.fnum = fnum1;
983 sinfo.rename_information.in.overwrite = true;
984 sinfo.rename_information.in.root_fid = 0;
985 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
986 status = smb_raw_setfileinfo(cli->tree, &sinfo);
987 if (torture_setting_bool(tctx, "samba4", false) ||
988 torture_setting_bool(tctx, "samba3", false)) {
989 /* why should this rename be considered invalid?? */
990 CHECK_STATUS(status, NT_STATUS_OK);
991 ret &= check_stream_list(tctx, cli, fname, 4, four);
992 } else {
993 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
994 ret &= check_stream_list(tctx, cli, fname, 5, five2);
998 /* TODO: we need to test more rename combinations */
1000 done:
1001 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1002 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1003 if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
1004 status = smbcli_unlink(cli->tree, fname);
1005 smbcli_deltree(cli->tree, BASEDIR);
1006 return ret;
1010 test stream names
1012 static bool test_stream_names2(struct torture_context *tctx,
1013 struct smbcli_state *cli)
1015 NTSTATUS status;
1016 union smb_open io;
1017 const char *fname = BASEDIR "\\stream_names2.txt";
1018 bool ret = true;
1019 int fnum1 = -1;
1020 uint8_t i;
1022 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1024 printf("(%s) testing stream names\n", __location__);
1025 io.generic.level = RAW_OPEN_NTCREATEX;
1026 io.ntcreatex.in.root_fid.fnum = 0;
1027 io.ntcreatex.in.flags = 0;
1028 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1029 io.ntcreatex.in.create_options = 0;
1030 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1031 io.ntcreatex.in.share_access = 0;
1032 io.ntcreatex.in.alloc_size = 0;
1033 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1034 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1035 io.ntcreatex.in.security_flags = 0;
1036 io.ntcreatex.in.fname = fname;
1037 status = smb_raw_open(cli->tree, tctx, &io);
1038 CHECK_STATUS(status, NT_STATUS_OK);
1039 fnum1 = io.ntcreatex.out.file.fnum;
1041 for (i=0x01; i < 0x7F; i++) {
1042 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1043 fname, i, i);
1044 NTSTATUS expected;
1046 switch (i) {
1047 case '/':/*0x2F*/
1048 case ':':/*0x3A*/
1049 case '\\':/*0x5C*/
1050 expected = NT_STATUS_OBJECT_NAME_INVALID;
1051 break;
1052 default:
1053 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1054 break;
1058 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1059 io.ntcreatex.in.fname = path;
1060 status = smb_raw_open(cli->tree, tctx, &io);
1061 if (!NT_STATUS_EQUAL(status, expected)) {
1062 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1063 __location__, fname, isprint(i)?(char)i:' ', i,
1064 isprint(i)?"":" (not printable)",
1065 nt_errstr(expected));
1067 CHECK_STATUS(status, expected);
1069 talloc_free(path);
1072 done:
1073 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1074 status = smbcli_unlink(cli->tree, fname);
1075 smbcli_deltree(cli->tree, BASEDIR);
1076 return ret;
1079 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1080 check_fnum = true; \
1081 call_name = #call; \
1082 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1083 sfinfo.generic.in.file.fnum = fnum; \
1084 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1085 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1086 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1087 nt_errstr(status), nt_errstr(rightstatus)); \
1088 ret = false; \
1090 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1091 finfo1.generic.in.file.fnum = fnum; \
1092 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1093 if (!NT_STATUS_IS_OK(status2)) { \
1094 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1095 ret = false; \
1096 }} while (0)
1099 test stream renames
1101 static bool test_stream_rename(struct torture_context *tctx,
1102 struct smbcli_state *cli)
1104 NTSTATUS status, status2;
1105 union smb_open io;
1106 const char *fname = BASEDIR "\\stream_rename.txt";
1107 const char *sname1, *sname2;
1108 union smb_fileinfo finfo1;
1109 union smb_setfileinfo sfinfo;
1110 bool ret = true;
1111 int fnum = -1;
1112 bool check_fnum;
1113 const char *call_name;
1115 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1117 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1118 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1120 printf("(%s) testing stream renames\n", __location__);
1121 io.generic.level = RAW_OPEN_NTCREATEX;
1122 io.ntcreatex.in.root_fid.fnum = 0;
1123 io.ntcreatex.in.flags = 0;
1124 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1125 SEC_FILE_WRITE_ATTRIBUTE |
1126 SEC_RIGHTS_FILE_ALL;
1127 io.ntcreatex.in.create_options = 0;
1128 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1129 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1130 io.ntcreatex.in.alloc_size = 0;
1131 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1132 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1133 io.ntcreatex.in.security_flags = 0;
1134 io.ntcreatex.in.fname = sname1;
1136 /* Create two streams. */
1137 status = smb_raw_open(cli->tree, tctx, &io);
1138 CHECK_STATUS(status, NT_STATUS_OK);
1139 fnum = io.ntcreatex.out.file.fnum;
1140 if (fnum != -1) smbcli_close(cli->tree, fnum);
1142 io.ntcreatex.in.fname = sname2;
1143 status = smb_raw_open(cli->tree, tctx, &io);
1144 CHECK_STATUS(status, NT_STATUS_OK);
1145 fnum = io.ntcreatex.out.file.fnum;
1147 if (fnum != -1) smbcli_close(cli->tree, fnum);
1150 * Open the second stream.
1153 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1154 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1155 status = smb_raw_open(cli->tree, tctx, &io);
1156 CHECK_STATUS(status, NT_STATUS_OK);
1157 fnum = io.ntcreatex.out.file.fnum;
1160 * Now rename the second stream onto the first.
1163 ZERO_STRUCT(sfinfo);
1165 sfinfo.rename_information.in.overwrite = 1;
1166 sfinfo.rename_information.in.root_fid = 0;
1167 sfinfo.rename_information.in.new_name = ":Stream One";
1168 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1170 done:
1171 if (fnum != -1) smbcli_close(cli->tree, fnum);
1172 status = smbcli_unlink(cli->tree, fname);
1173 smbcli_deltree(cli->tree, BASEDIR);
1174 return ret;
1177 static bool test_stream_rename2(struct torture_context *tctx,
1178 struct smbcli_state *cli)
1180 NTSTATUS status;
1181 union smb_open io;
1182 const char *fname1 = BASEDIR "\\stream.txt";
1183 const char *fname2 = BASEDIR "\\stream2.txt";
1184 const char *stream_name1 = ":Stream One:$DATA";
1185 const char *stream_name2 = ":Stream Two:$DATA";
1186 const char *stream_name_default = "::$DATA";
1187 const char *sname1;
1188 const char *sname2;
1189 bool ret = true;
1190 int fnum = -1;
1191 union smb_setfileinfo sinfo;
1192 union smb_rename rio;
1194 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1196 sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1197 sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1199 io.generic.level = RAW_OPEN_NTCREATEX;
1200 io.ntcreatex.in.root_fid.fnum = 0;
1201 io.ntcreatex.in.flags = 0;
1202 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1203 SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1204 io.ntcreatex.in.create_options = 0;
1205 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1206 io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1207 NTCREATEX_SHARE_ACCESS_WRITE |
1208 NTCREATEX_SHARE_ACCESS_DELETE);
1209 io.ntcreatex.in.alloc_size = 0;
1210 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1211 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1212 io.ntcreatex.in.security_flags = 0;
1213 io.ntcreatex.in.fname = sname1;
1215 /* Open/create new stream. */
1216 status = smb_raw_open(cli->tree, tctx, &io);
1217 CHECK_STATUS(status, NT_STATUS_OK);
1219 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1222 * Check raw rename with <base>:<stream>.
1224 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1225 __location__);
1226 rio.generic.level = RAW_RENAME_NTRENAME;
1227 rio.ntrename.in.old_name = sname1;
1228 rio.ntrename.in.new_name = sname2;
1229 rio.ntrename.in.attrib = 0;
1230 rio.ntrename.in.cluster_size = 0;
1231 rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1232 status = smb_raw_rename(cli->tree, &rio);
1233 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1236 * Check raw rename to the default stream using :<stream>.
1238 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1239 __location__);
1240 rio.ntrename.in.new_name = stream_name_default;
1241 status = smb_raw_rename(cli->tree, &rio);
1242 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1245 * Check raw rename using :<stream>.
1247 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1248 __location__);
1249 rio.ntrename.in.new_name = stream_name2;
1250 status = smb_raw_rename(cli->tree, &rio);
1251 CHECK_STATUS(status, NT_STATUS_OK);
1254 * Check raw rename of a stream to a file.
1256 printf("(%s) Checking NTRENAME of a stream to a file\n",
1257 __location__);
1258 rio.ntrename.in.old_name = sname2;
1259 rio.ntrename.in.new_name = fname2;
1260 status = smb_raw_rename(cli->tree, &rio);
1261 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1264 * Check raw rename of a file to a stream.
1266 printf("(%s) Checking NTRENAME of a file to a stream\n",
1267 __location__);
1269 /* Create the file. */
1270 io.ntcreatex.in.fname = fname2;
1271 status = smb_raw_open(cli->tree, tctx, &io);
1272 CHECK_STATUS(status, NT_STATUS_OK);
1273 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1275 /* Try the rename. */
1276 rio.ntrename.in.old_name = fname2;
1277 rio.ntrename.in.new_name = sname1;
1278 status = smb_raw_rename(cli->tree, &rio);
1279 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1282 * Reopen the stream for trans2 renames.
1284 io.ntcreatex.in.fname = sname2;
1285 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1286 status = smb_raw_open(cli->tree, tctx, &io);
1287 CHECK_STATUS(status, NT_STATUS_OK);
1288 fnum = io.ntcreatex.out.file.fnum;
1291 * Check trans2 rename of a stream using :<stream>.
1293 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1294 __location__);
1295 ZERO_STRUCT(sinfo);
1296 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1297 sinfo.rename_information.in.file.fnum = fnum;
1298 sinfo.rename_information.in.overwrite = 1;
1299 sinfo.rename_information.in.root_fid = 0;
1300 sinfo.rename_information.in.new_name = stream_name1;
1301 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1302 CHECK_STATUS(status, NT_STATUS_OK);
1305 * Check trans2 rename of an overwriting stream using :<stream>.
1307 printf("(%s) Checking trans2 rename of an overwriting stream using "
1308 ":<stream>\n", __location__);
1310 /* Create second stream. */
1311 io.ntcreatex.in.fname = sname2;
1312 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1313 status = smb_raw_open(cli->tree, tctx, &io);
1314 CHECK_STATUS(status, NT_STATUS_OK);
1315 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1317 /* Rename the first stream onto the second. */
1318 sinfo.rename_information.in.file.fnum = fnum;
1319 sinfo.rename_information.in.new_name = stream_name2;
1320 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1321 CHECK_STATUS(status, NT_STATUS_OK);
1323 smbcli_close(cli->tree, fnum);
1326 * Reopen the stream with the new name.
1328 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1329 io.ntcreatex.in.fname = sname2;
1330 status = smb_raw_open(cli->tree, tctx, &io);
1331 CHECK_STATUS(status, NT_STATUS_OK);
1332 fnum = io.ntcreatex.out.file.fnum;
1335 * Check trans2 rename of a stream using <base>:<stream>.
1337 printf("(%s) Checking trans2 rename of a stream using "
1338 "<base>:<stream>\n", __location__);
1339 sinfo.rename_information.in.file.fnum = fnum;
1340 sinfo.rename_information.in.new_name = sname1;
1341 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1342 CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1345 * Samba3 doesn't currently support renaming a stream to the default
1346 * stream. This test does pass on windows.
1348 if (torture_setting_bool(tctx, "samba3", false) ||
1349 torture_setting_bool(tctx, "samba4", false)) {
1350 goto done;
1354 * Check trans2 rename to the default stream using :<stream>.
1356 printf("(%s) Checking trans2 rename to defaualt stream using "
1357 ":<stream>\n", __location__);
1358 sinfo.rename_information.in.file.fnum = fnum;
1359 sinfo.rename_information.in.new_name = stream_name_default;
1360 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1361 CHECK_STATUS(status, NT_STATUS_OK);
1363 smbcli_close(cli->tree, fnum);
1365 done:
1366 smbcli_close(cli->tree, fnum);
1367 status = smbcli_unlink(cli->tree, fname1);
1368 status = smbcli_unlink(cli->tree, fname2);
1369 smbcli_deltree(cli->tree, BASEDIR);
1370 return ret;
1374 test stream renames
1376 static bool test_stream_rename3(struct torture_context *tctx,
1377 struct smbcli_state *cli)
1379 NTSTATUS status, status2;
1380 union smb_open io;
1381 const char *fname = BASEDIR "\\stream_rename.txt";
1382 const char *sname1, *sname2;
1383 union smb_fileinfo finfo1;
1384 union smb_setfileinfo sfinfo;
1385 bool ret = true;
1386 int fnum = -1;
1387 int fnum2 = -1;
1388 bool check_fnum;
1389 const char *call_name;
1391 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1393 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1394 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1396 printf("(%s) testing stream renames\n", __location__);
1397 io.generic.level = RAW_OPEN_NTCREATEX;
1398 io.ntcreatex.in.root_fid.fnum = 0;
1399 io.ntcreatex.in.flags = 0;
1400 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1401 SEC_FILE_WRITE_ATTRIBUTE |
1402 SEC_RIGHTS_FILE_ALL;
1403 io.ntcreatex.in.create_options = 0;
1404 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1405 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1406 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1407 io.ntcreatex.in.alloc_size = 0;
1408 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1409 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1410 io.ntcreatex.in.security_flags = 0;
1411 io.ntcreatex.in.fname = sname1;
1413 /* Create two streams. */
1414 status = smb_raw_open(cli->tree, tctx, &io);
1415 CHECK_STATUS(status, NT_STATUS_OK);
1416 fnum = io.ntcreatex.out.file.fnum;
1417 if (fnum != -1) smbcli_close(cli->tree, fnum);
1419 io.ntcreatex.in.fname = sname2;
1420 status = smb_raw_open(cli->tree, tctx, &io);
1421 CHECK_STATUS(status, NT_STATUS_OK);
1422 fnum = io.ntcreatex.out.file.fnum;
1424 if (fnum != -1) smbcli_close(cli->tree, fnum);
1426 /* open the second stream. */
1427 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1428 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1429 status = smb_raw_open(cli->tree, tctx, &io);
1430 CHECK_STATUS(status, NT_STATUS_OK);
1431 fnum = io.ntcreatex.out.file.fnum;
1433 /* Keep a handle to the first stream open. */
1434 io.ntcreatex.in.fname = sname1;
1435 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1436 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1437 status = smb_raw_open(cli->tree, tctx, &io);
1438 CHECK_STATUS(status, NT_STATUS_OK);
1439 fnum2 = io.ntcreatex.out.file.fnum;
1441 ZERO_STRUCT(sfinfo);
1442 sfinfo.rename_information.in.overwrite = 1;
1443 sfinfo.rename_information.in.root_fid = 0;
1444 sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1445 if (torture_setting_bool(tctx, "samba4", false) ||
1446 torture_setting_bool(tctx, "samba3", false)) {
1447 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1448 } else {
1449 CHECK_CALL_FNUM(RENAME_INFORMATION,
1450 NT_STATUS_INVALID_PARAMETER);
1454 done:
1455 if (fnum != -1) smbcli_close(cli->tree, fnum);
1456 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1457 status = smbcli_unlink(cli->tree, fname);
1458 smbcli_deltree(cli->tree, BASEDIR);
1459 return ret;
1462 static bool create_file_with_stream(struct torture_context *tctx,
1463 struct smbcli_state *cli,
1464 const char *stream)
1466 NTSTATUS status;
1467 bool ret = true;
1468 union smb_open io;
1470 /* Create a file with a stream */
1471 io.generic.level = RAW_OPEN_NTCREATEX;
1472 io.ntcreatex.in.root_fid.fnum = 0;
1473 io.ntcreatex.in.flags = 0;
1474 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1475 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1476 io.ntcreatex.in.create_options = 0;
1477 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1478 io.ntcreatex.in.share_access = 0;
1479 io.ntcreatex.in.alloc_size = 0;
1480 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1481 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1482 io.ntcreatex.in.security_flags = 0;
1483 io.ntcreatex.in.fname = stream;
1485 status = smb_raw_open(cli->tree, tctx, &io);
1486 CHECK_STATUS(status, NT_STATUS_OK);
1488 done:
1489 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1490 return ret;
1493 /* Test how streams interact with create dispositions */
1494 static bool test_stream_create_disposition(struct torture_context *tctx,
1495 struct smbcli_state *cli)
1497 NTSTATUS status;
1498 union smb_open io;
1499 const char *fname = BASEDIR "\\stream.txt";
1500 const char *stream = "Stream One:$DATA";
1501 const char *fname_stream;
1502 const char *default_stream_name = "::$DATA";
1503 const char *stream_list[2];
1504 bool ret = false;
1505 int fnum = -1;
1507 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1509 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1511 stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1512 stream_list[1] = default_stream_name;
1514 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1515 goto done;
1518 /* Open the base file with OPEN */
1519 io.generic.level = RAW_OPEN_NTCREATEX;
1520 io.ntcreatex.in.root_fid.fnum = 0;
1521 io.ntcreatex.in.flags = 0;
1522 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1523 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1524 io.ntcreatex.in.create_options = 0;
1525 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1526 io.ntcreatex.in.share_access = 0;
1527 io.ntcreatex.in.alloc_size = 0;
1528 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1529 io.ntcreatex.in.security_flags = 0;
1530 io.ntcreatex.in.fname = fname;
1533 * check ntcreatex open: sanity check
1535 printf("(%s) Checking ntcreatex disp: open\n", __location__);
1536 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1537 status = smb_raw_open(cli->tree, tctx, &io);
1538 CHECK_STATUS(status, NT_STATUS_OK);
1539 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1540 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1541 goto done;
1545 * check ntcreatex overwrite
1547 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1548 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1549 status = smb_raw_open(cli->tree, tctx, &io);
1550 CHECK_STATUS(status, NT_STATUS_OK);
1551 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1552 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1553 goto done;
1557 * check ntcreatex overwrite_if
1559 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1560 smbcli_unlink(cli->tree, fname);
1561 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1562 goto done;
1565 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1566 status = smb_raw_open(cli->tree, tctx, &io);
1567 CHECK_STATUS(status, NT_STATUS_OK);
1568 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1569 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1570 goto done;
1574 * check ntcreatex supersede
1576 printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1577 smbcli_unlink(cli->tree, fname);
1578 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1579 goto done;
1582 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1583 status = smb_raw_open(cli->tree, tctx, &io);
1584 CHECK_STATUS(status, NT_STATUS_OK);
1585 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1586 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1587 goto done;
1591 * check ntcreatex overwrite_if on a stream.
1593 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1594 __location__);
1595 smbcli_unlink(cli->tree, fname);
1596 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1597 goto done;
1600 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1601 io.ntcreatex.in.fname = fname_stream;
1602 status = smb_raw_open(cli->tree, tctx, &io);
1603 CHECK_STATUS(status, NT_STATUS_OK);
1604 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1605 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1606 goto done;
1610 * check openx overwrite_if
1612 printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1613 smbcli_unlink(cli->tree, fname);
1614 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1615 goto done;
1618 io.openx.level = RAW_OPEN_OPENX;
1619 io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1620 io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1621 io.openx.in.search_attrs = 0;
1622 io.openx.in.file_attrs = 0;
1623 io.openx.in.write_time = 0;
1624 io.openx.in.size = 1024*1024;
1625 io.openx.in.timeout = 0;
1626 io.openx.in.fname = fname;
1628 io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1629 status = smb_raw_open(cli->tree, tctx, &io);
1630 CHECK_STATUS(status, NT_STATUS_OK);
1631 smbcli_close(cli->tree, io.openx.out.file.fnum);
1632 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1633 goto done;
1636 ret = true;
1638 done:
1639 smbcli_close(cli->tree, fnum);
1640 smbcli_unlink(cli->tree, fname);
1641 smbcli_deltree(cli->tree, BASEDIR);
1642 return ret;
1645 #if 0
1646 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1647 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1648 struct smbcli_state *cli)
1650 #define LONG_STREAM_SIZE 2
1651 char *lstream_name;
1652 const char *fname = BASEDIR "\\stream.txt";
1653 const char *fname_stream;
1654 NTSTATUS status;
1655 bool ret = true;
1656 int i;
1657 union smb_fileinfo finfo;
1659 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1661 lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1663 for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1664 lstream_name[i] = (char)('a' + i%26);
1666 lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1668 torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1669 for (i = 0; i < 10000; i++) {
1670 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1671 lstream_name, i);
1672 ret = create_file_with_stream(tctx, cli, fname_stream);
1673 if (!ret) {
1674 goto done;
1678 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1679 finfo.generic.in.file.path = fname;
1681 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1682 CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1684 done:
1685 smbcli_unlink(cli->tree, fname);
1686 smbcli_deltree(cli->tree, BASEDIR);
1687 return ret;
1689 #endif
1691 /* Test the effect of setting attributes on a stream. */
1692 static bool test_stream_attributes(struct torture_context *tctx,
1693 struct smbcli_state *cli)
1695 bool ret = true;
1696 NTSTATUS status;
1697 union smb_open io;
1698 const char *fname = BASEDIR "\\stream_attr.txt";
1699 const char *stream = "Stream One:$DATA";
1700 const char *fname_stream;
1701 int fnum = -1;
1702 union smb_fileinfo finfo;
1703 union smb_setfileinfo sfinfo;
1704 time_t basetime = (time(NULL) - 86400) & ~1;
1706 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1708 torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1710 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1712 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1713 ret = create_file_with_stream(tctx, cli, fname_stream);
1714 if (!ret) {
1715 goto done;
1718 ZERO_STRUCT(finfo);
1719 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1720 finfo.generic.in.file.path = fname;
1721 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1722 CHECK_STATUS(status, NT_STATUS_OK);
1724 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
1726 /* Now open the stream name. */
1728 io.generic.level = RAW_OPEN_NTCREATEX;
1729 io.ntcreatex.in.root_fid.fnum = 0;
1730 io.ntcreatex.in.flags = 0;
1731 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1732 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1733 io.ntcreatex.in.create_options = 0;
1734 io.ntcreatex.in.file_attr = 0;
1735 io.ntcreatex.in.share_access = 0;
1736 io.ntcreatex.in.alloc_size = 0;
1737 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1738 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1739 io.ntcreatex.in.security_flags = 0;
1740 io.ntcreatex.in.fname = fname_stream;
1742 status = smb_raw_open(cli->tree, tctx, &io);
1743 CHECK_STATUS(status, NT_STATUS_OK);
1745 fnum = io.ntcreatex.out.file.fnum;
1747 /* Change the attributes + time on the stream fnum. */
1748 ZERO_STRUCT(sfinfo);
1749 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1750 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1752 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1753 sfinfo.generic.in.file.fnum = fnum;
1754 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1755 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_setfileinfo failed");
1757 smbcli_close(cli->tree, fnum);
1758 fnum = -1;
1760 ZERO_STRUCT(finfo);
1761 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1762 finfo.generic.in.file.path = fname;
1763 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1764 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_pathinfo failed");
1766 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_READONLY, ret, done, "attrib incorrect");
1768 torture_assert_int_equal_goto(tctx, nt_time_to_unix(finfo.all_info.out.write_time), basetime, ret, done, "time incorrect");
1770 done:
1772 if (fnum != -1) {
1773 smbcli_close(cli->tree, fnum);
1775 smbcli_unlink(cli->tree, fname);
1776 smbcli_deltree(cli->tree, BASEDIR);
1777 return ret;
1781 * A rough approximation of how a windows client creates the streams for use
1782 * in the summary tab.
1784 static bool test_stream_summary_tab(struct torture_context *tctx,
1785 struct smbcli_state *cli)
1787 bool ret = true;
1788 NTSTATUS status;
1789 union smb_open io;
1790 const char *fname = BASEDIR "\\stream_summary.txt";
1791 const char *stream = ":\005SummaryInformation:$DATA";
1792 const char *fname_stream = NULL;
1793 const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1794 const char *fname_tmp_stream = NULL;
1795 int fnum = -1;
1796 union smb_fileinfo finfo;
1797 union smb_rename rio;
1798 ssize_t retsize;
1800 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1802 fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1803 fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1804 tmp_stream);
1806 /* Create summary info stream */
1807 ret = create_file_with_stream(tctx, cli, fname_stream);
1808 if (!ret) {
1809 goto done;
1812 /* Create summary info tmp update stream */
1813 ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1814 if (!ret) {
1815 goto done;
1818 /* Open tmp stream and write to it */
1819 io.generic.level = RAW_OPEN_NTCREATEX;
1820 io.ntcreatex.in.root_fid.fnum = 0;
1821 io.ntcreatex.in.flags = 0;
1822 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1823 io.ntcreatex.in.create_options = 0;
1824 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1825 io.ntcreatex.in.share_access = 0;
1826 io.ntcreatex.in.alloc_size = 0;
1827 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1828 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1829 io.ntcreatex.in.security_flags = 0;
1830 io.ntcreatex.in.fname = fname_tmp_stream;
1832 status = smb_raw_open(cli->tree, tctx, &io);
1833 CHECK_STATUS(status, NT_STATUS_OK);
1834 fnum = io.ntcreatex.out.file.fnum;
1836 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1837 CHECK_VALUE(retsize, 9);
1839 /* close the tmp stream. */
1840 smbcli_close(cli->tree, fnum);
1841 fnum = -1;
1843 /* Delete the current stream */
1844 smbcli_unlink(cli->tree, fname_stream);
1846 /* Do the rename. */
1847 rio.generic.level = RAW_RENAME_RENAME;
1848 rio.rename.in.pattern1 = fname_tmp_stream;
1849 rio.rename.in.pattern2 = stream;
1850 rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1851 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1852 status = smb_raw_rename(cli->tree, &rio);
1853 CHECK_STATUS(status, NT_STATUS_OK);
1855 /* Try to open the tmp stream that we just renamed away. */
1856 status = smb_raw_open(cli->tree, tctx, &io);
1857 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1859 /* Query the base file to make sure it's still there. */
1860 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1861 finfo.generic.in.file.path = fname;
1863 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1864 CHECK_STATUS(status, NT_STATUS_OK);
1866 done:
1868 if (fnum != -1) {
1869 smbcli_close(cli->tree, fnum);
1871 smbcli_unlink(cli->tree, fname);
1873 smbcli_deltree(cli->tree, BASEDIR);
1874 return ret;
1878 basic testing of streams calls
1880 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
1882 struct torture_suite *suite = torture_suite_create(tctx, "streams");
1884 torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
1885 torture_suite_add_1smb_test(suite, "io", test_stream_io);
1886 torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
1887 torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
1888 torture_suite_add_1smb_test(suite, "names", test_stream_names);
1889 torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
1890 torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
1891 torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
1892 torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
1893 torture_suite_add_1smb_test(suite, "createdisp",
1894 test_stream_create_disposition);
1895 torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
1896 torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
1898 #if 0
1899 torture_suite_add_1smb_test(suite, "LARGESTREAMINFO",
1900 test_stream_large_streaminfo);
1901 #endif
1903 return suite;