docs: man smbtorture: Add missing meta data.
[Samba/gebeck_regimport.git] / source4 / torture / raw / streams.c
blob1611c642b48c57ba9694145ee44e2d06b42dae69
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 info;
650 union smb_fileinfo finfo;
651 union smb_fileinfo stinfo;
652 union smb_setfileinfo sinfo;
653 const char *fname = BASEDIR "\\stream_names.txt";
654 const char *sname1, *sname1b, *sname1c, *sname1d;
655 const char *sname2, *snamew, *snamew2;
656 const char *snamer1, *snamer2;
657 bool ret = true;
658 int fnum1 = -1;
659 int fnum2 = -1;
660 int fnum3 = -1;
661 int i;
662 const char *four[4] = {
663 "::$DATA",
664 ":\x05Stream\n One:$DATA",
665 ":MStream Two:$DATA",
666 ":?Stream*:$DATA"
668 const char *five1[5] = {
669 "::$DATA",
670 ":\x05Stream\n One:$DATA",
671 ":BeforeRename:$DATA",
672 ":MStream Two:$DATA",
673 ":?Stream*:$DATA"
675 const char *five2[5] = {
676 "::$DATA",
677 ":\x05Stream\n One:$DATA",
678 ":AfterRename:$DATA",
679 ":MStream Two:$DATA",
680 ":?Stream*:$DATA"
683 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
685 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
686 sname1b = talloc_asprintf(tctx, "%s:", sname1);
687 sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
688 sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
689 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
690 snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
691 snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
692 snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
693 snamer2 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "AfterRename");
695 printf("(%s) testing stream names\n", __location__);
696 io.generic.level = RAW_OPEN_NTCREATEX;
697 io.ntcreatex.in.root_fid.fnum = 0;
698 io.ntcreatex.in.flags = 0;
699 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
700 io.ntcreatex.in.create_options = 0;
701 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
702 io.ntcreatex.in.share_access =
703 NTCREATEX_SHARE_ACCESS_READ |
704 NTCREATEX_SHARE_ACCESS_WRITE;
705 io.ntcreatex.in.alloc_size = 0;
706 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
707 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
708 io.ntcreatex.in.security_flags = 0;
709 io.ntcreatex.in.fname = fname;
711 status = smb_raw_open(cli->tree, tctx, &io);
712 CHECK_STATUS(status, NT_STATUS_OK);
713 fnum1 = io.ntcreatex.out.file.fnum;
715 torture_comment(tctx, "Adding two EAs to base file\n");
716 ZERO_STRUCT(sinfo);
717 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
718 sinfo.generic.in.file.fnum = fnum1;
719 sinfo.ea_set.in.num_eas = 2;
720 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
721 sinfo.ea_set.in.eas[0].flags = 0;
722 sinfo.ea_set.in.eas[0].name.s = "EAONE";
723 sinfo.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
724 sinfo.ea_set.in.eas[1].flags = 0;
725 sinfo.ea_set.in.eas[1].name.s = "SECONDEA";
726 sinfo.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
728 status = smb_raw_setfileinfo(cli->tree, &sinfo);
729 CHECK_STATUS(status, NT_STATUS_OK);
732 * Make sure the create time of the streams are different from the
733 * base file.
735 sleep(2);
736 smbcli_close(cli->tree, fnum1);
738 io.generic.level = RAW_OPEN_NTCREATEX;
739 io.ntcreatex.in.root_fid.fnum = 0;
740 io.ntcreatex.in.flags = 0;
741 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
742 io.ntcreatex.in.create_options = 0;
743 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
744 io.ntcreatex.in.share_access =
745 NTCREATEX_SHARE_ACCESS_READ |
746 NTCREATEX_SHARE_ACCESS_WRITE;
747 io.ntcreatex.in.alloc_size = 0;
748 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
749 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
750 io.ntcreatex.in.security_flags = 0;
751 io.ntcreatex.in.fname = sname1;
753 status = smb_raw_open(cli->tree, tctx, &io);
754 CHECK_STATUS(status, NT_STATUS_OK);
755 fnum1 = io.ntcreatex.out.file.fnum;
757 torture_comment(tctx, "Adding one EAs to first stream file\n");
758 ZERO_STRUCT(sinfo);
759 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
760 sinfo.generic.in.file.fnum = fnum1;
761 sinfo.ea_set.in.num_eas = 1;
762 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 1);
763 sinfo.ea_set.in.eas[0].flags = 0;
764 sinfo.ea_set.in.eas[0].name.s = "STREAMEA";
765 sinfo.ea_set.in.eas[0].value = data_blob_string_const("EA_VALUE1");
767 status = smb_raw_setfileinfo(cli->tree, &sinfo);
768 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
770 status = torture_check_ea(cli, sname1, "STREAMEA", "EA_VALUE1");
771 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
773 ZERO_STRUCT(info);
774 info.generic.level = RAW_FILEINFO_ALL_EAS;
775 info.all_eas.in.file.path = sname1;
777 status = smb_raw_pathinfo(cli->tree, tctx, &info);
778 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
781 * A different stream does not give a sharing violation
784 io.ntcreatex.in.fname = sname2;
785 status = smb_raw_open(cli->tree, tctx, &io);
786 CHECK_STATUS(status, NT_STATUS_OK);
787 fnum2 = io.ntcreatex.out.file.fnum;
790 * ... whereas the same stream does with unchanged access/share_access
791 * flags
794 io.ntcreatex.in.fname = sname1;
795 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
796 status = smb_raw_open(cli->tree, tctx, &io);
797 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
799 io.ntcreatex.in.fname = sname1b;
800 status = smb_raw_open(cli->tree, tctx, &io);
801 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
803 io.ntcreatex.in.fname = sname1c;
804 status = smb_raw_open(cli->tree, tctx, &io);
805 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
806 /* w2k returns INVALID_PARAMETER */
807 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
808 } else {
809 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
812 io.ntcreatex.in.fname = sname1d;
813 status = smb_raw_open(cli->tree, tctx, &io);
814 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
815 /* w2k returns INVALID_PARAMETER */
816 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
817 } else {
818 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
821 io.ntcreatex.in.fname = sname2;
822 status = smb_raw_open(cli->tree, tctx, &io);
823 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
825 io.ntcreatex.in.fname = snamew;
826 status = smb_raw_open(cli->tree, tctx, &io);
827 CHECK_STATUS(status, NT_STATUS_OK);
828 fnum3 = io.ntcreatex.out.file.fnum;
830 io.ntcreatex.in.fname = snamew2;
831 status = smb_raw_open(cli->tree, tctx, &io);
832 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
834 ret &= check_stream_list(tctx, cli, fname, 4, four);
836 smbcli_close(cli->tree, fnum1);
837 smbcli_close(cli->tree, fnum2);
838 smbcli_close(cli->tree, fnum3);
840 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
841 finfo.generic.in.file.path = fname;
842 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
843 CHECK_STATUS(status, NT_STATUS_OK);
845 ret &= check_stream_list(tctx, cli, fname, 4, four);
847 for (i=0; i < 4; i++) {
848 NTTIME write_time;
849 uint64_t stream_size;
850 char *path = talloc_asprintf(tctx, "%s%s",
851 fname, four[i]);
853 char *rpath = talloc_strdup(path, path);
854 char *p = strrchr(rpath, ':');
855 /* eat :$DATA */
856 *p = 0;
857 p--;
858 if (*p == ':') {
859 /* eat ::$DATA */
860 *p = 0;
862 printf("(%s): i[%u][%s]\n", __location__, i, path);
863 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
864 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
865 SEC_FILE_WRITE_ATTRIBUTE |
866 SEC_RIGHTS_FILE_ALL;
867 io.ntcreatex.in.fname = path;
868 status = smb_raw_open(cli->tree, tctx, &io);
869 CHECK_STATUS(status, NT_STATUS_OK);
870 fnum1 = io.ntcreatex.out.file.fnum;
872 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
873 finfo.generic.in.file.path = fname;
874 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
875 CHECK_STATUS(status, NT_STATUS_OK);
877 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
878 stinfo.generic.in.file.fnum = fnum1;
879 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
880 CHECK_STATUS(status, NT_STATUS_OK);
881 if (!torture_setting_bool(tctx, "samba3", false)) {
882 CHECK_NTTIME(stinfo.all_info.out.create_time,
883 finfo.all_info.out.create_time);
884 CHECK_NTTIME(stinfo.all_info.out.access_time,
885 finfo.all_info.out.access_time);
886 CHECK_NTTIME(stinfo.all_info.out.write_time,
887 finfo.all_info.out.write_time);
888 CHECK_NTTIME(stinfo.all_info.out.change_time,
889 finfo.all_info.out.change_time);
891 CHECK_VALUE(stinfo.all_info.out.attrib,
892 finfo.all_info.out.attrib);
893 CHECK_VALUE(stinfo.all_info.out.size,
894 finfo.all_info.out.size);
895 CHECK_VALUE(stinfo.all_info.out.delete_pending,
896 finfo.all_info.out.delete_pending);
897 CHECK_VALUE(stinfo.all_info.out.directory,
898 finfo.all_info.out.directory);
899 CHECK_VALUE(stinfo.all_info.out.ea_size,
900 finfo.all_info.out.ea_size);
902 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
903 stinfo.generic.in.file.fnum = fnum1;
904 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
905 CHECK_STATUS(status, NT_STATUS_OK);
906 if (!torture_setting_bool(tctx, "samba3", false)) {
907 CHECK_STR(stinfo.name_info.out.fname.s, rpath);
910 write_time = finfo.all_info.out.write_time;
911 write_time += i*1000000;
912 write_time /= 1000000;
913 write_time *= 1000000;
915 ZERO_STRUCT(sinfo);
916 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
917 sinfo.basic_info.in.file.fnum = fnum1;
918 sinfo.basic_info.in.write_time = write_time;
919 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
920 status = smb_raw_setfileinfo(cli->tree, &sinfo);
921 CHECK_STATUS(status, NT_STATUS_OK);
923 stream_size = i*8192;
925 ZERO_STRUCT(sinfo);
926 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
927 sinfo.end_of_file_info.in.file.fnum = fnum1;
928 sinfo.end_of_file_info.in.size = stream_size;
929 status = smb_raw_setfileinfo(cli->tree, &sinfo);
930 CHECK_STATUS(status, NT_STATUS_OK);
932 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
933 stinfo.generic.in.file.fnum = fnum1;
934 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
935 CHECK_STATUS(status, NT_STATUS_OK);
936 if (!torture_setting_bool(tctx, "samba3", false)) {
937 CHECK_NTTIME(stinfo.all_info.out.write_time,
938 write_time);
939 CHECK_VALUE(stinfo.all_info.out.attrib,
940 finfo.all_info.out.attrib);
942 CHECK_VALUE(stinfo.all_info.out.size,
943 stream_size);
944 CHECK_VALUE(stinfo.all_info.out.delete_pending,
945 finfo.all_info.out.delete_pending);
946 CHECK_VALUE(stinfo.all_info.out.directory,
947 finfo.all_info.out.directory);
948 CHECK_VALUE(stinfo.all_info.out.ea_size,
949 finfo.all_info.out.ea_size);
951 ret &= check_stream_list(tctx, cli, fname, 4, four);
953 smbcli_close(cli->tree, fnum1);
954 talloc_free(path);
957 printf("(%s): testing stream renames\n", __location__);
958 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
959 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
960 SEC_FILE_WRITE_ATTRIBUTE |
961 SEC_RIGHTS_FILE_ALL;
962 io.ntcreatex.in.fname = snamer1;
963 status = smb_raw_open(cli->tree, tctx, &io);
964 CHECK_STATUS(status, NT_STATUS_OK);
965 fnum1 = io.ntcreatex.out.file.fnum;
967 ret &= check_stream_list(tctx, cli, fname, 5, five1);
969 ZERO_STRUCT(sinfo);
970 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
971 sinfo.rename_information.in.file.fnum = fnum1;
972 sinfo.rename_information.in.overwrite = true;
973 sinfo.rename_information.in.root_fid = 0;
974 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
975 status = smb_raw_setfileinfo(cli->tree, &sinfo);
976 CHECK_STATUS(status, NT_STATUS_OK);
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 = false;
984 sinfo.rename_information.in.root_fid = 0;
985 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
986 status = smb_raw_setfileinfo(cli->tree, &sinfo);
987 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
989 ret &= check_stream_list(tctx, cli, fname, 5, five2);
991 ZERO_STRUCT(sinfo);
992 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
993 sinfo.rename_information.in.file.fnum = fnum1;
994 sinfo.rename_information.in.overwrite = true;
995 sinfo.rename_information.in.root_fid = 0;
996 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
997 status = smb_raw_setfileinfo(cli->tree, &sinfo);
998 if (torture_setting_bool(tctx, "samba4", false) ||
999 torture_setting_bool(tctx, "samba3", false)) {
1000 /* why should this rename be considered invalid?? */
1001 CHECK_STATUS(status, NT_STATUS_OK);
1002 ret &= check_stream_list(tctx, cli, fname, 4, four);
1003 } else {
1004 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1005 ret &= check_stream_list(tctx, cli, fname, 5, five2);
1009 /* TODO: we need to test more rename combinations */
1011 done:
1012 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1013 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1014 if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
1015 status = smbcli_unlink(cli->tree, fname);
1016 smbcli_deltree(cli->tree, BASEDIR);
1017 return ret;
1021 test stream names
1023 static bool test_stream_names2(struct torture_context *tctx,
1024 struct smbcli_state *cli)
1026 NTSTATUS status;
1027 union smb_open io;
1028 const char *fname = BASEDIR "\\stream_names2.txt";
1029 bool ret = true;
1030 int fnum1 = -1;
1031 uint8_t i;
1033 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1035 printf("(%s) testing stream names\n", __location__);
1036 io.generic.level = RAW_OPEN_NTCREATEX;
1037 io.ntcreatex.in.root_fid.fnum = 0;
1038 io.ntcreatex.in.flags = 0;
1039 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1040 io.ntcreatex.in.create_options = 0;
1041 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1042 io.ntcreatex.in.share_access = 0;
1043 io.ntcreatex.in.alloc_size = 0;
1044 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1045 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1046 io.ntcreatex.in.security_flags = 0;
1047 io.ntcreatex.in.fname = fname;
1048 status = smb_raw_open(cli->tree, tctx, &io);
1049 CHECK_STATUS(status, NT_STATUS_OK);
1050 fnum1 = io.ntcreatex.out.file.fnum;
1052 for (i=0x01; i < 0x7F; i++) {
1053 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1054 fname, i, i);
1055 NTSTATUS expected;
1057 switch (i) {
1058 case '/':/*0x2F*/
1059 case ':':/*0x3A*/
1060 case '\\':/*0x5C*/
1061 expected = NT_STATUS_OBJECT_NAME_INVALID;
1062 break;
1063 default:
1064 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1065 break;
1069 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1070 io.ntcreatex.in.fname = path;
1071 status = smb_raw_open(cli->tree, tctx, &io);
1072 if (!NT_STATUS_EQUAL(status, expected)) {
1073 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1074 __location__, fname, isprint(i)?(char)i:' ', i,
1075 isprint(i)?"":" (not printable)",
1076 nt_errstr(expected));
1078 CHECK_STATUS(status, expected);
1080 talloc_free(path);
1083 done:
1084 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1085 status = smbcli_unlink(cli->tree, fname);
1086 smbcli_deltree(cli->tree, BASEDIR);
1087 return ret;
1090 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1091 check_fnum = true; \
1092 call_name = #call; \
1093 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1094 sfinfo.generic.in.file.fnum = fnum; \
1095 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1096 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1097 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1098 nt_errstr(status), nt_errstr(rightstatus)); \
1099 ret = false; \
1101 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1102 finfo1.generic.in.file.fnum = fnum; \
1103 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1104 if (!NT_STATUS_IS_OK(status2)) { \
1105 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1106 ret = false; \
1107 }} while (0)
1110 test stream renames
1112 static bool test_stream_rename(struct torture_context *tctx,
1113 struct smbcli_state *cli)
1115 NTSTATUS status, status2;
1116 union smb_open io;
1117 const char *fname = BASEDIR "\\stream_rename.txt";
1118 const char *sname1, *sname2;
1119 union smb_fileinfo finfo1;
1120 union smb_setfileinfo sfinfo;
1121 bool ret = true;
1122 int fnum = -1;
1123 bool check_fnum;
1124 const char *call_name;
1126 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1128 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1129 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1131 printf("(%s) testing stream renames\n", __location__);
1132 io.generic.level = RAW_OPEN_NTCREATEX;
1133 io.ntcreatex.in.root_fid.fnum = 0;
1134 io.ntcreatex.in.flags = 0;
1135 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1136 SEC_FILE_WRITE_ATTRIBUTE |
1137 SEC_RIGHTS_FILE_ALL;
1138 io.ntcreatex.in.create_options = 0;
1139 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1140 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1141 io.ntcreatex.in.alloc_size = 0;
1142 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1143 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1144 io.ntcreatex.in.security_flags = 0;
1145 io.ntcreatex.in.fname = sname1;
1147 /* Create two streams. */
1148 status = smb_raw_open(cli->tree, tctx, &io);
1149 CHECK_STATUS(status, NT_STATUS_OK);
1150 fnum = io.ntcreatex.out.file.fnum;
1151 if (fnum != -1) smbcli_close(cli->tree, fnum);
1153 io.ntcreatex.in.fname = sname2;
1154 status = smb_raw_open(cli->tree, tctx, &io);
1155 CHECK_STATUS(status, NT_STATUS_OK);
1156 fnum = io.ntcreatex.out.file.fnum;
1158 if (fnum != -1) smbcli_close(cli->tree, fnum);
1161 * Open the second stream.
1164 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1165 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1166 status = smb_raw_open(cli->tree, tctx, &io);
1167 CHECK_STATUS(status, NT_STATUS_OK);
1168 fnum = io.ntcreatex.out.file.fnum;
1171 * Now rename the second stream onto the first.
1174 ZERO_STRUCT(sfinfo);
1176 sfinfo.rename_information.in.overwrite = 1;
1177 sfinfo.rename_information.in.root_fid = 0;
1178 sfinfo.rename_information.in.new_name = ":Stream One";
1179 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1181 done:
1182 if (fnum != -1) smbcli_close(cli->tree, fnum);
1183 status = smbcli_unlink(cli->tree, fname);
1184 smbcli_deltree(cli->tree, BASEDIR);
1185 return ret;
1188 static bool test_stream_rename2(struct torture_context *tctx,
1189 struct smbcli_state *cli)
1191 NTSTATUS status;
1192 union smb_open io;
1193 const char *fname1 = BASEDIR "\\stream.txt";
1194 const char *fname2 = BASEDIR "\\stream2.txt";
1195 const char *stream_name1 = ":Stream One:$DATA";
1196 const char *stream_name2 = ":Stream Two:$DATA";
1197 const char *stream_name_default = "::$DATA";
1198 const char *sname1;
1199 const char *sname2;
1200 bool ret = true;
1201 int fnum = -1;
1202 union smb_setfileinfo sinfo;
1203 union smb_rename rio;
1205 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1207 sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1208 sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1210 io.generic.level = RAW_OPEN_NTCREATEX;
1211 io.ntcreatex.in.root_fid.fnum = 0;
1212 io.ntcreatex.in.flags = 0;
1213 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1214 SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1215 io.ntcreatex.in.create_options = 0;
1216 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1217 io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1218 NTCREATEX_SHARE_ACCESS_WRITE |
1219 NTCREATEX_SHARE_ACCESS_DELETE);
1220 io.ntcreatex.in.alloc_size = 0;
1221 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1222 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1223 io.ntcreatex.in.security_flags = 0;
1224 io.ntcreatex.in.fname = sname1;
1226 /* Open/create new stream. */
1227 status = smb_raw_open(cli->tree, tctx, &io);
1228 CHECK_STATUS(status, NT_STATUS_OK);
1230 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1233 * Check raw rename with <base>:<stream>.
1235 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1236 __location__);
1237 rio.generic.level = RAW_RENAME_NTRENAME;
1238 rio.ntrename.in.old_name = sname1;
1239 rio.ntrename.in.new_name = sname2;
1240 rio.ntrename.in.attrib = 0;
1241 rio.ntrename.in.cluster_size = 0;
1242 rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1243 status = smb_raw_rename(cli->tree, &rio);
1244 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1247 * Check raw rename to the default stream using :<stream>.
1249 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1250 __location__);
1251 rio.ntrename.in.new_name = stream_name_default;
1252 status = smb_raw_rename(cli->tree, &rio);
1253 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1256 * Check raw rename using :<stream>.
1258 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1259 __location__);
1260 rio.ntrename.in.new_name = stream_name2;
1261 status = smb_raw_rename(cli->tree, &rio);
1262 CHECK_STATUS(status, NT_STATUS_OK);
1265 * Check raw rename of a stream to a file.
1267 printf("(%s) Checking NTRENAME of a stream to a file\n",
1268 __location__);
1269 rio.ntrename.in.old_name = sname2;
1270 rio.ntrename.in.new_name = fname2;
1271 status = smb_raw_rename(cli->tree, &rio);
1272 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1275 * Check raw rename of a file to a stream.
1277 printf("(%s) Checking NTRENAME of a file to a stream\n",
1278 __location__);
1280 /* Create the file. */
1281 io.ntcreatex.in.fname = fname2;
1282 status = smb_raw_open(cli->tree, tctx, &io);
1283 CHECK_STATUS(status, NT_STATUS_OK);
1284 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1286 /* Try the rename. */
1287 rio.ntrename.in.old_name = fname2;
1288 rio.ntrename.in.new_name = sname1;
1289 status = smb_raw_rename(cli->tree, &rio);
1290 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1293 * Reopen the stream for trans2 renames.
1295 io.ntcreatex.in.fname = sname2;
1296 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1297 status = smb_raw_open(cli->tree, tctx, &io);
1298 CHECK_STATUS(status, NT_STATUS_OK);
1299 fnum = io.ntcreatex.out.file.fnum;
1302 * Check trans2 rename of a stream using :<stream>.
1304 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1305 __location__);
1306 ZERO_STRUCT(sinfo);
1307 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1308 sinfo.rename_information.in.file.fnum = fnum;
1309 sinfo.rename_information.in.overwrite = 1;
1310 sinfo.rename_information.in.root_fid = 0;
1311 sinfo.rename_information.in.new_name = stream_name1;
1312 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1313 CHECK_STATUS(status, NT_STATUS_OK);
1316 * Check trans2 rename of an overwriting stream using :<stream>.
1318 printf("(%s) Checking trans2 rename of an overwriting stream using "
1319 ":<stream>\n", __location__);
1321 /* Create second stream. */
1322 io.ntcreatex.in.fname = sname2;
1323 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1324 status = smb_raw_open(cli->tree, tctx, &io);
1325 CHECK_STATUS(status, NT_STATUS_OK);
1326 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1328 /* Rename the first stream onto the second. */
1329 sinfo.rename_information.in.file.fnum = fnum;
1330 sinfo.rename_information.in.new_name = stream_name2;
1331 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1332 CHECK_STATUS(status, NT_STATUS_OK);
1334 smbcli_close(cli->tree, fnum);
1337 * Reopen the stream with the new name.
1339 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1340 io.ntcreatex.in.fname = sname2;
1341 status = smb_raw_open(cli->tree, tctx, &io);
1342 CHECK_STATUS(status, NT_STATUS_OK);
1343 fnum = io.ntcreatex.out.file.fnum;
1346 * Check trans2 rename of a stream using <base>:<stream>.
1348 printf("(%s) Checking trans2 rename of a stream using "
1349 "<base>:<stream>\n", __location__);
1350 sinfo.rename_information.in.file.fnum = fnum;
1351 sinfo.rename_information.in.new_name = sname1;
1352 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1353 CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1356 * Samba3 doesn't currently support renaming a stream to the default
1357 * stream. This test does pass on windows.
1359 if (torture_setting_bool(tctx, "samba3", false) ||
1360 torture_setting_bool(tctx, "samba4", false)) {
1361 goto done;
1365 * Check trans2 rename to the default stream using :<stream>.
1367 printf("(%s) Checking trans2 rename to defaualt stream using "
1368 ":<stream>\n", __location__);
1369 sinfo.rename_information.in.file.fnum = fnum;
1370 sinfo.rename_information.in.new_name = stream_name_default;
1371 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1372 CHECK_STATUS(status, NT_STATUS_OK);
1374 smbcli_close(cli->tree, fnum);
1376 done:
1377 smbcli_close(cli->tree, fnum);
1378 status = smbcli_unlink(cli->tree, fname1);
1379 status = smbcli_unlink(cli->tree, fname2);
1380 smbcli_deltree(cli->tree, BASEDIR);
1381 return ret;
1385 test stream renames
1387 static bool test_stream_rename3(struct torture_context *tctx,
1388 struct smbcli_state *cli)
1390 NTSTATUS status, status2;
1391 union smb_open io;
1392 const char *fname = BASEDIR "\\stream_rename.txt";
1393 const char *sname1, *sname2;
1394 union smb_fileinfo finfo1;
1395 union smb_setfileinfo sfinfo;
1396 bool ret = true;
1397 int fnum = -1;
1398 int fnum2 = -1;
1399 bool check_fnum;
1400 const char *call_name;
1402 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1404 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1405 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1407 printf("(%s) testing stream renames\n", __location__);
1408 io.generic.level = RAW_OPEN_NTCREATEX;
1409 io.ntcreatex.in.root_fid.fnum = 0;
1410 io.ntcreatex.in.flags = 0;
1411 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1412 SEC_FILE_WRITE_ATTRIBUTE |
1413 SEC_RIGHTS_FILE_ALL;
1414 io.ntcreatex.in.create_options = 0;
1415 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1416 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1417 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1418 io.ntcreatex.in.alloc_size = 0;
1419 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1420 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1421 io.ntcreatex.in.security_flags = 0;
1422 io.ntcreatex.in.fname = sname1;
1424 /* Create two streams. */
1425 status = smb_raw_open(cli->tree, tctx, &io);
1426 CHECK_STATUS(status, NT_STATUS_OK);
1427 fnum = io.ntcreatex.out.file.fnum;
1428 if (fnum != -1) smbcli_close(cli->tree, fnum);
1430 io.ntcreatex.in.fname = sname2;
1431 status = smb_raw_open(cli->tree, tctx, &io);
1432 CHECK_STATUS(status, NT_STATUS_OK);
1433 fnum = io.ntcreatex.out.file.fnum;
1435 if (fnum != -1) smbcli_close(cli->tree, fnum);
1437 /* open the second stream. */
1438 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1439 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1440 status = smb_raw_open(cli->tree, tctx, &io);
1441 CHECK_STATUS(status, NT_STATUS_OK);
1442 fnum = io.ntcreatex.out.file.fnum;
1444 /* Keep a handle to the first stream open. */
1445 io.ntcreatex.in.fname = sname1;
1446 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1447 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1448 status = smb_raw_open(cli->tree, tctx, &io);
1449 CHECK_STATUS(status, NT_STATUS_OK);
1450 fnum2 = io.ntcreatex.out.file.fnum;
1452 ZERO_STRUCT(sfinfo);
1453 sfinfo.rename_information.in.overwrite = 1;
1454 sfinfo.rename_information.in.root_fid = 0;
1455 sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1456 if (torture_setting_bool(tctx, "samba4", false) ||
1457 torture_setting_bool(tctx, "samba3", false)) {
1458 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1459 } else {
1460 CHECK_CALL_FNUM(RENAME_INFORMATION,
1461 NT_STATUS_INVALID_PARAMETER);
1465 done:
1466 if (fnum != -1) smbcli_close(cli->tree, fnum);
1467 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1468 status = smbcli_unlink(cli->tree, fname);
1469 smbcli_deltree(cli->tree, BASEDIR);
1470 return ret;
1473 static bool create_file_with_stream(struct torture_context *tctx,
1474 struct smbcli_state *cli,
1475 const char *stream)
1477 NTSTATUS status;
1478 bool ret = true;
1479 union smb_open io;
1481 /* Create a file with a stream */
1482 io.generic.level = RAW_OPEN_NTCREATEX;
1483 io.ntcreatex.in.root_fid.fnum = 0;
1484 io.ntcreatex.in.flags = 0;
1485 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1486 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1487 io.ntcreatex.in.create_options = 0;
1488 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1489 io.ntcreatex.in.share_access = 0;
1490 io.ntcreatex.in.alloc_size = 0;
1491 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1492 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1493 io.ntcreatex.in.security_flags = 0;
1494 io.ntcreatex.in.fname = stream;
1496 status = smb_raw_open(cli->tree, tctx, &io);
1497 CHECK_STATUS(status, NT_STATUS_OK);
1499 done:
1500 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1501 return ret;
1504 /* Test how streams interact with create dispositions */
1505 static bool test_stream_create_disposition(struct torture_context *tctx,
1506 struct smbcli_state *cli)
1508 NTSTATUS status;
1509 union smb_open io;
1510 const char *fname = BASEDIR "\\stream.txt";
1511 const char *stream = "Stream One:$DATA";
1512 const char *fname_stream;
1513 const char *default_stream_name = "::$DATA";
1514 const char *stream_list[2];
1515 bool ret = false;
1516 int fnum = -1;
1518 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1520 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1522 stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1523 stream_list[1] = default_stream_name;
1525 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1526 goto done;
1529 /* Open the base file with OPEN */
1530 io.generic.level = RAW_OPEN_NTCREATEX;
1531 io.ntcreatex.in.root_fid.fnum = 0;
1532 io.ntcreatex.in.flags = 0;
1533 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1534 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1535 io.ntcreatex.in.create_options = 0;
1536 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1537 io.ntcreatex.in.share_access = 0;
1538 io.ntcreatex.in.alloc_size = 0;
1539 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1540 io.ntcreatex.in.security_flags = 0;
1541 io.ntcreatex.in.fname = fname;
1544 * check ntcreatex open: sanity check
1546 printf("(%s) Checking ntcreatex disp: open\n", __location__);
1547 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1548 status = smb_raw_open(cli->tree, tctx, &io);
1549 CHECK_STATUS(status, NT_STATUS_OK);
1550 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1551 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1552 goto done;
1556 * check ntcreatex overwrite
1558 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1559 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1560 status = smb_raw_open(cli->tree, tctx, &io);
1561 CHECK_STATUS(status, NT_STATUS_OK);
1562 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1563 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1564 goto done;
1568 * check ntcreatex overwrite_if
1570 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1571 smbcli_unlink(cli->tree, fname);
1572 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1573 goto done;
1576 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1577 status = smb_raw_open(cli->tree, tctx, &io);
1578 CHECK_STATUS(status, NT_STATUS_OK);
1579 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1580 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1581 goto done;
1585 * check ntcreatex supersede
1587 printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1588 smbcli_unlink(cli->tree, fname);
1589 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1590 goto done;
1593 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1594 status = smb_raw_open(cli->tree, tctx, &io);
1595 CHECK_STATUS(status, NT_STATUS_OK);
1596 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1597 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1598 goto done;
1602 * check ntcreatex overwrite_if on a stream.
1604 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1605 __location__);
1606 smbcli_unlink(cli->tree, fname);
1607 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1608 goto done;
1611 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1612 io.ntcreatex.in.fname = fname_stream;
1613 status = smb_raw_open(cli->tree, tctx, &io);
1614 CHECK_STATUS(status, NT_STATUS_OK);
1615 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1616 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1617 goto done;
1621 * check openx overwrite_if
1623 printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1624 smbcli_unlink(cli->tree, fname);
1625 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1626 goto done;
1629 io.openx.level = RAW_OPEN_OPENX;
1630 io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1631 io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1632 io.openx.in.search_attrs = 0;
1633 io.openx.in.file_attrs = 0;
1634 io.openx.in.write_time = 0;
1635 io.openx.in.size = 1024*1024;
1636 io.openx.in.timeout = 0;
1637 io.openx.in.fname = fname;
1639 io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1640 status = smb_raw_open(cli->tree, tctx, &io);
1641 CHECK_STATUS(status, NT_STATUS_OK);
1642 smbcli_close(cli->tree, io.openx.out.file.fnum);
1643 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1644 goto done;
1647 ret = true;
1649 done:
1650 smbcli_close(cli->tree, fnum);
1651 smbcli_unlink(cli->tree, fname);
1652 smbcli_deltree(cli->tree, BASEDIR);
1653 return ret;
1656 #if 0
1657 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1658 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1659 struct smbcli_state *cli)
1661 #define LONG_STREAM_SIZE 2
1662 char *lstream_name;
1663 const char *fname = BASEDIR "\\stream.txt";
1664 const char *fname_stream;
1665 NTSTATUS status;
1666 bool ret = true;
1667 int i;
1668 union smb_fileinfo finfo;
1670 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1672 lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1674 for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1675 lstream_name[i] = (char)('a' + i%26);
1677 lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1679 torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1680 for (i = 0; i < 10000; i++) {
1681 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1682 lstream_name, i);
1683 ret = create_file_with_stream(tctx, cli, fname_stream);
1684 if (!ret) {
1685 goto done;
1689 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1690 finfo.generic.in.file.path = fname;
1692 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1693 CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1695 done:
1696 smbcli_unlink(cli->tree, fname);
1697 smbcli_deltree(cli->tree, BASEDIR);
1698 return ret;
1700 #endif
1702 /* Test the effect of setting attributes on a stream. */
1703 static bool test_stream_attributes(struct torture_context *tctx,
1704 struct smbcli_state *cli)
1706 bool ret = true;
1707 NTSTATUS status;
1708 union smb_open io;
1709 const char *fname = BASEDIR "\\stream_attr.txt";
1710 const char *stream = "Stream One:$DATA";
1711 const char *fname_stream;
1712 int fnum = -1;
1713 union smb_fileinfo finfo;
1714 union smb_setfileinfo sfinfo;
1715 time_t basetime = (time(NULL) - 86400) & ~1;
1717 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1719 torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1721 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1723 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1724 ret = create_file_with_stream(tctx, cli, fname_stream);
1725 if (!ret) {
1726 goto done;
1729 ZERO_STRUCT(finfo);
1730 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1731 finfo.generic.in.file.path = fname;
1732 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1733 CHECK_STATUS(status, NT_STATUS_OK);
1735 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
1737 /* Now open the stream name. */
1739 io.generic.level = RAW_OPEN_NTCREATEX;
1740 io.ntcreatex.in.root_fid.fnum = 0;
1741 io.ntcreatex.in.flags = 0;
1742 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1743 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1744 io.ntcreatex.in.create_options = 0;
1745 io.ntcreatex.in.file_attr = 0;
1746 io.ntcreatex.in.share_access = 0;
1747 io.ntcreatex.in.alloc_size = 0;
1748 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1749 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1750 io.ntcreatex.in.security_flags = 0;
1751 io.ntcreatex.in.fname = fname_stream;
1753 status = smb_raw_open(cli->tree, tctx, &io);
1754 CHECK_STATUS(status, NT_STATUS_OK);
1756 fnum = io.ntcreatex.out.file.fnum;
1758 /* Change the attributes + time on the stream fnum. */
1759 ZERO_STRUCT(sfinfo);
1760 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1761 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1763 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1764 sfinfo.generic.in.file.fnum = fnum;
1765 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1766 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_setfileinfo failed");
1768 smbcli_close(cli->tree, fnum);
1769 fnum = -1;
1771 ZERO_STRUCT(finfo);
1772 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1773 finfo.generic.in.file.path = fname;
1774 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1775 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_pathinfo failed");
1777 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_READONLY, ret, done, "attrib incorrect");
1779 torture_assert_int_equal_goto(tctx, nt_time_to_unix(finfo.all_info.out.write_time), basetime, ret, done, "time incorrect");
1781 done:
1783 if (fnum != -1) {
1784 smbcli_close(cli->tree, fnum);
1786 smbcli_unlink(cli->tree, fname);
1787 smbcli_deltree(cli->tree, BASEDIR);
1788 return ret;
1792 * A rough approximation of how a windows client creates the streams for use
1793 * in the summary tab.
1795 static bool test_stream_summary_tab(struct torture_context *tctx,
1796 struct smbcli_state *cli)
1798 bool ret = true;
1799 NTSTATUS status;
1800 union smb_open io;
1801 const char *fname = BASEDIR "\\stream_summary.txt";
1802 const char *stream = ":\005SummaryInformation:$DATA";
1803 const char *fname_stream = NULL;
1804 const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1805 const char *fname_tmp_stream = NULL;
1806 int fnum = -1;
1807 union smb_fileinfo finfo;
1808 union smb_rename rio;
1809 ssize_t retsize;
1811 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1813 fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1814 fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1815 tmp_stream);
1817 /* Create summary info stream */
1818 ret = create_file_with_stream(tctx, cli, fname_stream);
1819 if (!ret) {
1820 goto done;
1823 /* Create summary info tmp update stream */
1824 ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1825 if (!ret) {
1826 goto done;
1829 /* Open tmp stream and write to it */
1830 io.generic.level = RAW_OPEN_NTCREATEX;
1831 io.ntcreatex.in.root_fid.fnum = 0;
1832 io.ntcreatex.in.flags = 0;
1833 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1834 io.ntcreatex.in.create_options = 0;
1835 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1836 io.ntcreatex.in.share_access = 0;
1837 io.ntcreatex.in.alloc_size = 0;
1838 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1839 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1840 io.ntcreatex.in.security_flags = 0;
1841 io.ntcreatex.in.fname = fname_tmp_stream;
1843 status = smb_raw_open(cli->tree, tctx, &io);
1844 CHECK_STATUS(status, NT_STATUS_OK);
1845 fnum = io.ntcreatex.out.file.fnum;
1847 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1848 CHECK_VALUE(retsize, 9);
1850 /* close the tmp stream. */
1851 smbcli_close(cli->tree, fnum);
1852 fnum = -1;
1854 /* Delete the current stream */
1855 smbcli_unlink(cli->tree, fname_stream);
1857 /* Do the rename. */
1858 rio.generic.level = RAW_RENAME_RENAME;
1859 rio.rename.in.pattern1 = fname_tmp_stream;
1860 rio.rename.in.pattern2 = stream;
1861 rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1862 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1863 status = smb_raw_rename(cli->tree, &rio);
1864 CHECK_STATUS(status, NT_STATUS_OK);
1866 /* Try to open the tmp stream that we just renamed away. */
1867 status = smb_raw_open(cli->tree, tctx, &io);
1868 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1870 /* Query the base file to make sure it's still there. */
1871 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1872 finfo.generic.in.file.path = fname;
1874 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1875 CHECK_STATUS(status, NT_STATUS_OK);
1877 done:
1879 if (fnum != -1) {
1880 smbcli_close(cli->tree, fnum);
1882 smbcli_unlink(cli->tree, fname);
1884 smbcli_deltree(cli->tree, BASEDIR);
1885 return ret;
1889 basic testing of streams calls
1891 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
1893 struct torture_suite *suite = torture_suite_create(tctx, "streams");
1895 torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
1896 torture_suite_add_1smb_test(suite, "io", test_stream_io);
1897 torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
1898 torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
1899 torture_suite_add_1smb_test(suite, "names", test_stream_names);
1900 torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
1901 torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
1902 torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
1903 torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
1904 torture_suite_add_1smb_test(suite, "createdisp",
1905 test_stream_create_disposition);
1906 torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
1907 torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
1909 #if 0
1910 torture_suite_add_1smb_test(suite, "LARGESTREAMINFO",
1911 test_stream_large_streaminfo);
1912 #endif
1914 return suite;