s3-waf: remove version from libpdb.so for now.
[Samba/vl.git] / source4 / torture / raw / streams.c
blobae3bc2a7131a9bf02a4924922ec86946d13f6b15
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 if (!torture_setup_dir(cli, BASEDIR)) {
202 return false;
205 basedir_data = talloc_asprintf(tctx, "%s::$DATA", BASEDIR);
206 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
208 printf("(%s) opening non-existant directory stream\n", __location__);
209 io.generic.level = RAW_OPEN_NTCREATEX;
210 io.ntcreatex.in.root_fid.fnum = 0;
211 io.ntcreatex.in.flags = 0;
212 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
213 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
214 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
215 io.ntcreatex.in.share_access = 0;
216 io.ntcreatex.in.alloc_size = 0;
217 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
218 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
219 io.ntcreatex.in.security_flags = 0;
220 io.ntcreatex.in.fname = sname1;
221 status = smb_raw_open(cli->tree, tctx, &io);
222 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
224 printf("(%s) opening basedir stream\n", __location__);
225 io.generic.level = RAW_OPEN_NTCREATEX;
226 io.ntcreatex.in.root_fid.fnum = 0;
227 io.ntcreatex.in.flags = 0;
228 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
229 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
230 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
231 io.ntcreatex.in.share_access = 0;
232 io.ntcreatex.in.alloc_size = 0;
233 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
234 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
235 io.ntcreatex.in.security_flags = 0;
236 io.ntcreatex.in.fname = basedir_data;
237 status = smb_raw_open(cli->tree, tctx, &io);
238 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
240 printf("(%s) opening basedir ::$DATA stream\n", __location__);
241 io.generic.level = RAW_OPEN_NTCREATEX;
242 io.ntcreatex.in.root_fid.fnum = 0;
243 io.ntcreatex.in.flags = 0x10;
244 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
245 io.ntcreatex.in.create_options = 0;
246 io.ntcreatex.in.file_attr = 0;
247 io.ntcreatex.in.share_access = 0;
248 io.ntcreatex.in.alloc_size = 0;
249 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
250 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
251 io.ntcreatex.in.security_flags = 0;
252 io.ntcreatex.in.fname = basedir_data;
253 status = smb_raw_open(cli->tree, tctx, &io);
254 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
256 printf("(%s) list the streams on the basedir\n", __location__);
257 ret &= check_stream_list(tctx, cli, BASEDIR, 0, NULL);
258 done:
259 smbcli_deltree(cli->tree, BASEDIR);
260 return ret;
264 test basic behavior of streams on directories
266 static bool test_stream_io(struct torture_context *tctx,
267 struct smbcli_state *cli)
269 NTSTATUS status;
270 union smb_open io;
271 const char *fname = BASEDIR "\\stream.txt";
272 const char *sname1, *sname2;
273 bool ret = true;
274 int fnum = -1;
275 ssize_t retsize;
277 const char *one[] = { "::$DATA" };
278 const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
279 const char *three[] = { "::$DATA", ":Stream One:$DATA",
280 ":Second Stream:$DATA" };
282 if (!torture_setup_dir(cli, BASEDIR)) {
283 return false;
286 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
287 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
289 printf("(%s) creating a stream on a non-existant file\n", __location__);
290 io.generic.level = RAW_OPEN_NTCREATEX;
291 io.ntcreatex.in.root_fid.fnum = 0;
292 io.ntcreatex.in.flags = 0;
293 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
294 io.ntcreatex.in.create_options = 0;
295 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
296 io.ntcreatex.in.share_access = 0;
297 io.ntcreatex.in.alloc_size = 0;
298 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
299 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
300 io.ntcreatex.in.security_flags = 0;
301 io.ntcreatex.in.fname = sname1;
302 status = smb_raw_open(cli->tree, tctx, &io);
303 CHECK_STATUS(status, NT_STATUS_OK);
304 fnum = io.ntcreatex.out.file.fnum;
306 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", NULL);
308 printf("(%s) check that open of base file is allowed\n", __location__);
309 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
310 io.ntcreatex.in.fname = fname;
311 status = smb_raw_open(cli->tree, tctx, &io);
312 CHECK_STATUS(status, NT_STATUS_OK);
313 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
315 printf("(%s) writing to stream\n", __location__);
316 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
317 CHECK_VALUE(retsize, 9);
319 smbcli_close(cli->tree, fnum);
321 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test data");
323 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
324 io.ntcreatex.in.fname = sname1;
325 status = smb_raw_open(cli->tree, tctx, &io);
326 CHECK_STATUS(status, NT_STATUS_OK);
327 fnum = io.ntcreatex.out.file.fnum;
329 printf("(%s) modifying stream\n", __location__);
330 retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
331 CHECK_VALUE(retsize, 10);
333 smbcli_close(cli->tree, fnum);
335 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$FOO", NULL);
337 printf("(%s) creating a stream2 on a existing file\n", __location__);
338 io.ntcreatex.in.fname = sname2;
339 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
340 status = smb_raw_open(cli->tree, tctx, &io);
341 CHECK_STATUS(status, NT_STATUS_OK);
342 fnum = io.ntcreatex.out.file.fnum;
344 printf("(%s) modifying stream\n", __location__);
345 retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
346 CHECK_VALUE(retsize, 13);
348 smbcli_close(cli->tree, fnum);
350 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test MORE DATA ");
351 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$DATA", "test MORE DATA ");
352 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:", NULL);
353 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream", "SECOND STREAM");
354 ret &= check_stream(cli, __location__, tctx, fname,
355 "SECOND STREAM:$DATA", "SECOND STREAM");
356 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$DATA", "SECOND STREAM");
357 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:", NULL);
358 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$FOO", NULL);
360 check_stream_list(tctx, cli, fname, 3, three);
362 printf("(%s) deleting stream\n", __location__);
363 status = smbcli_unlink(cli->tree, sname1);
364 CHECK_STATUS(status, NT_STATUS_OK);
366 check_stream_list(tctx, cli, fname, 2, two);
368 printf("(%s) delete a stream via delete-on-close\n", __location__);
369 io.ntcreatex.in.fname = sname2;
370 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
371 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
372 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
373 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
375 status = smb_raw_open(cli->tree, tctx, &io);
376 CHECK_STATUS(status, NT_STATUS_OK);
377 fnum = io.ntcreatex.out.file.fnum;
379 smbcli_close(cli->tree, fnum);
380 status = smbcli_unlink(cli->tree, sname2);
381 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
383 check_stream_list(tctx, cli, fname, 1, one);
385 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
386 io.ntcreatex.in.fname = sname1;
387 status = smb_raw_open(cli->tree, tctx, &io);
388 CHECK_STATUS(status, NT_STATUS_OK);
389 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
390 io.ntcreatex.in.fname = sname2;
391 status = smb_raw_open(cli->tree, tctx, &io);
392 CHECK_STATUS(status, NT_STATUS_OK);
393 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
395 printf("(%s) deleting file\n", __location__);
396 status = smbcli_unlink(cli->tree, fname);
397 CHECK_STATUS(status, NT_STATUS_OK);
399 done:
400 smbcli_close(cli->tree, fnum);
401 smbcli_deltree(cli->tree, BASEDIR);
402 return ret;
406 test stream sharemodes
408 static bool test_stream_sharemodes(struct torture_context *tctx,
409 struct smbcli_state *cli)
411 NTSTATUS status;
412 union smb_open io;
413 const char *fname = BASEDIR "\\stream.txt";
414 const char *sname1, *sname2;
415 bool ret = true;
416 int fnum1 = -1;
417 int fnum2 = -1;
419 if (!torture_setup_dir(cli, BASEDIR)) {
420 return false;
423 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
424 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
426 printf("(%s) testing stream share mode conflicts\n", __location__);
427 io.generic.level = RAW_OPEN_NTCREATEX;
428 io.ntcreatex.in.root_fid.fnum = 0;
429 io.ntcreatex.in.flags = 0;
430 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
431 io.ntcreatex.in.create_options = 0;
432 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
433 io.ntcreatex.in.share_access = 0;
434 io.ntcreatex.in.alloc_size = 0;
435 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
436 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
437 io.ntcreatex.in.security_flags = 0;
438 io.ntcreatex.in.fname = sname1;
440 status = smb_raw_open(cli->tree, tctx, &io);
441 CHECK_STATUS(status, NT_STATUS_OK);
442 fnum1 = io.ntcreatex.out.file.fnum;
445 * A different stream does not give a sharing violation
448 io.ntcreatex.in.fname = sname2;
449 status = smb_raw_open(cli->tree, tctx, &io);
450 CHECK_STATUS(status, NT_STATUS_OK);
451 fnum2 = io.ntcreatex.out.file.fnum;
454 * ... whereas the same stream does with unchanged access/share_access
455 * flags
458 io.ntcreatex.in.fname = sname1;
459 io.ntcreatex.in.open_disposition = 0;
460 status = smb_raw_open(cli->tree, tctx, &io);
461 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
463 io.ntcreatex.in.fname = sname2;
464 status = smb_raw_open(cli->tree, tctx, &io);
465 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
467 done:
468 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
469 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
470 status = smbcli_unlink(cli->tree, fname);
471 smbcli_deltree(cli->tree, BASEDIR);
472 return ret;
476 * Test FILE_SHARE_DELETE on streams
478 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
479 * with SEC_STD_DELETE.
481 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
482 * be opened with SEC_STD_DELETE.
484 * A stream held open with FILE_SHARE_DELETE allows the file to be
485 * deleted. After the main file is deleted, access to the open file descriptor
486 * still works, but all name-based access to both the main file as well as the
487 * stream is denied with DELETE ending.
489 * This means, an open of the main file with SEC_STD_DELETE should walk all
490 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
491 * SHARING_VIOLATION, the main open fails.
493 * Closing the main file after delete_on_close has been set does not really
494 * unlink it but leaves the corresponding share mode entry with
495 * delete_on_close being set around until all streams are closed.
497 * Opening a stream must also look at the main file's share mode entry, look
498 * at the delete_on_close bit and potentially return DELETE_PENDING.
501 static bool test_stream_delete(struct torture_context *tctx,
502 struct smbcli_state *cli)
504 NTSTATUS status;
505 union smb_open io;
506 const char *fname = BASEDIR "\\stream.txt";
507 const char *sname1;
508 bool ret = true;
509 int fnum = -1;
510 uint8_t buf[9];
511 ssize_t retsize;
512 union smb_fileinfo finfo;
514 if (!torture_setup_dir(cli, BASEDIR)) {
515 return false;
518 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
520 printf("(%s) opening non-existant file stream\n", __location__);
521 io.generic.level = RAW_OPEN_NTCREATEX;
522 io.ntcreatex.in.root_fid.fnum = 0;
523 io.ntcreatex.in.flags = 0;
524 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
525 io.ntcreatex.in.create_options = 0;
526 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
527 io.ntcreatex.in.share_access = 0;
528 io.ntcreatex.in.alloc_size = 0;
529 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
530 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
531 io.ntcreatex.in.security_flags = 0;
532 io.ntcreatex.in.fname = sname1;
534 status = smb_raw_open(cli->tree, tctx, &io);
535 CHECK_STATUS(status, NT_STATUS_OK);
536 fnum = io.ntcreatex.out.file.fnum;
538 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
539 CHECK_VALUE(retsize, 9);
542 * One stream opened without FILE_SHARE_DELETE prevents the main file
543 * to be deleted or even opened with DELETE access
546 status = smbcli_unlink(cli->tree, fname);
547 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
549 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
550 io.ntcreatex.in.fname = fname;
551 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
552 status = smb_raw_open(cli->tree, tctx, &io);
553 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
555 smbcli_close(cli->tree, fnum);
558 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
561 io.ntcreatex.in.fname = sname1;
562 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
563 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
564 status = smb_raw_open(cli->tree, tctx, &io);
565 CHECK_STATUS(status, NT_STATUS_OK);
566 fnum = io.ntcreatex.out.file.fnum;
568 status = smbcli_unlink(cli->tree, fname);
569 CHECK_STATUS(status, NT_STATUS_OK);
572 * file access still works on the stream while the main file is closed
575 retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
576 CHECK_VALUE(retsize, 9);
578 finfo.generic.level = RAW_FILEINFO_STANDARD;
579 finfo.generic.in.file.path = fname;
582 * name-based access to both the main file and the stream does not
583 * work anymore but gives DELETE_PENDING
586 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
587 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
590 * older S3 doesn't do this
592 finfo.generic.in.file.path = sname1;
593 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
594 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
597 * fd-based qfileinfo on the stream still works, the stream does not
598 * have the delete-on-close bit set. This could mean that open on the
599 * stream first opens the main file
602 finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
603 finfo.all_info.in.file.fnum = fnum;
605 status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
606 CHECK_STATUS(status, NT_STATUS_OK);
608 /* w2k and w2k3 return 0 and w2k8 returns 1 */
609 if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) ||
610 TARGET_IS_SAMBA3(tctx)) {
611 CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
612 } else {
613 CHECK_VALUE(finfo.all_info.out.delete_pending, 1);
616 smbcli_close(cli->tree, fnum);
619 * After closing the stream the file is really gone.
622 finfo.generic.in.file.path = fname;
623 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
624 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
626 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA
627 |SEC_STD_DELETE;
628 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
629 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
630 status = smb_raw_open(cli->tree, tctx, &io);
631 CHECK_STATUS(status, NT_STATUS_OK);
632 fnum = io.ntcreatex.out.file.fnum;
634 finfo.generic.in.file.path = fname;
635 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
636 CHECK_STATUS(status, NT_STATUS_OK);
638 smbcli_close(cli->tree, fnum);
640 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
641 CHECK_STATUS(status, NT_STATUS_OK);
642 done:
643 smbcli_close(cli->tree, fnum);
644 smbcli_unlink(cli->tree, fname);
645 smbcli_deltree(cli->tree, BASEDIR);
646 return ret;
650 test stream names
652 static bool test_stream_names(struct torture_context *tctx,
653 struct smbcli_state *cli)
655 NTSTATUS status;
656 union smb_open io;
657 union smb_fileinfo finfo;
658 union smb_fileinfo stinfo;
659 union smb_setfileinfo sinfo;
660 const char *fname = BASEDIR "\\stream_names.txt";
661 const char *sname1, *sname1b, *sname1c, *sname1d;
662 const char *sname2, *snamew, *snamew2;
663 const char *snamer1, *snamer2;
664 bool ret = true;
665 int fnum1 = -1;
666 int fnum2 = -1;
667 int fnum3 = -1;
668 int i;
669 const char *four[4] = {
670 "::$DATA",
671 ":\x05Stream\n One:$DATA",
672 ":MStream Two:$DATA",
673 ":?Stream*:$DATA"
675 const char *five1[5] = {
676 "::$DATA",
677 ":\x05Stream\n One:$DATA",
678 ":BeforeRename:$DATA",
679 ":MStream Two:$DATA",
680 ":?Stream*:$DATA"
682 const char *five2[5] = {
683 "::$DATA",
684 ":\x05Stream\n One:$DATA",
685 ":AfterRename:$DATA",
686 ":MStream Two:$DATA",
687 ":?Stream*:$DATA"
690 if (!torture_setup_dir(cli, BASEDIR)) {
691 return false;
694 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
695 sname1b = talloc_asprintf(tctx, "%s:", sname1);
696 sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
697 sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
698 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
699 snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
700 snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
701 snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
702 snamer2 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "AfterRename");
704 printf("(%s) testing stream names\n", __location__);
705 io.generic.level = RAW_OPEN_NTCREATEX;
706 io.ntcreatex.in.root_fid.fnum = 0;
707 io.ntcreatex.in.flags = 0;
708 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
709 io.ntcreatex.in.create_options = 0;
710 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
711 io.ntcreatex.in.share_access = 0;
712 io.ntcreatex.in.alloc_size = 0;
713 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
714 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
715 io.ntcreatex.in.security_flags = 0;
716 io.ntcreatex.in.fname = fname;
718 status = smb_raw_open(cli->tree, tctx, &io);
719 CHECK_STATUS(status, NT_STATUS_OK);
720 fnum1 = io.ntcreatex.out.file.fnum;
723 * Make sure the create time of the streams are different from the
724 * base file.
726 sleep(2);
727 smbcli_close(cli->tree, fnum1);
729 io.generic.level = RAW_OPEN_NTCREATEX;
730 io.ntcreatex.in.root_fid.fnum = 0;
731 io.ntcreatex.in.flags = 0;
732 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
733 io.ntcreatex.in.create_options = 0;
734 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
735 io.ntcreatex.in.share_access = 0;
736 io.ntcreatex.in.alloc_size = 0;
737 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
738 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
739 io.ntcreatex.in.security_flags = 0;
740 io.ntcreatex.in.fname = sname1;
742 status = smb_raw_open(cli->tree, tctx, &io);
743 CHECK_STATUS(status, NT_STATUS_OK);
744 fnum1 = io.ntcreatex.out.file.fnum;
747 * A different stream does not give a sharing violation
750 io.ntcreatex.in.fname = sname2;
751 status = smb_raw_open(cli->tree, tctx, &io);
752 CHECK_STATUS(status, NT_STATUS_OK);
753 fnum2 = io.ntcreatex.out.file.fnum;
756 * ... whereas the same stream does with unchanged access/share_access
757 * flags
760 io.ntcreatex.in.fname = sname1;
761 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
762 status = smb_raw_open(cli->tree, tctx, &io);
763 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
765 io.ntcreatex.in.fname = sname1b;
766 status = smb_raw_open(cli->tree, tctx, &io);
767 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
769 io.ntcreatex.in.fname = sname1c;
770 status = smb_raw_open(cli->tree, tctx, &io);
771 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
772 /* w2k returns INVALID_PARAMETER */
773 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
774 } else {
775 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
778 io.ntcreatex.in.fname = sname1d;
779 status = smb_raw_open(cli->tree, tctx, &io);
780 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
781 /* w2k returns INVALID_PARAMETER */
782 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
783 } else {
784 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
787 io.ntcreatex.in.fname = sname2;
788 status = smb_raw_open(cli->tree, tctx, &io);
789 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
791 io.ntcreatex.in.fname = snamew;
792 status = smb_raw_open(cli->tree, tctx, &io);
793 CHECK_STATUS(status, NT_STATUS_OK);
794 fnum3 = io.ntcreatex.out.file.fnum;
796 io.ntcreatex.in.fname = snamew2;
797 status = smb_raw_open(cli->tree, tctx, &io);
798 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
800 ret &= check_stream_list(tctx, cli, fname, 4, four);
802 smbcli_close(cli->tree, fnum1);
803 smbcli_close(cli->tree, fnum2);
804 smbcli_close(cli->tree, fnum3);
806 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
807 finfo.generic.in.file.path = fname;
808 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
809 CHECK_STATUS(status, NT_STATUS_OK);
811 ret &= check_stream_list(tctx, cli, fname, 4, four);
813 for (i=0; i < 4; i++) {
814 NTTIME write_time;
815 uint64_t stream_size;
816 char *path = talloc_asprintf(tctx, "%s%s",
817 fname, four[i]);
819 char *rpath = talloc_strdup(path, path);
820 char *p = strrchr(rpath, ':');
821 /* eat :$DATA */
822 *p = 0;
823 p--;
824 if (*p == ':') {
825 /* eat ::$DATA */
826 *p = 0;
828 printf("(%s): i[%u][%s]\n", __location__, i, path);
829 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
830 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
831 SEC_FILE_WRITE_ATTRIBUTE |
832 SEC_RIGHTS_FILE_ALL;
833 io.ntcreatex.in.fname = path;
834 status = smb_raw_open(cli->tree, tctx, &io);
835 CHECK_STATUS(status, NT_STATUS_OK);
836 fnum1 = io.ntcreatex.out.file.fnum;
838 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
839 finfo.generic.in.file.path = fname;
840 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
841 CHECK_STATUS(status, NT_STATUS_OK);
843 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
844 stinfo.generic.in.file.fnum = fnum1;
845 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
846 CHECK_STATUS(status, NT_STATUS_OK);
847 if (!torture_setting_bool(tctx, "samba3", false)) {
848 CHECK_NTTIME(stinfo.all_info.out.create_time,
849 finfo.all_info.out.create_time);
850 CHECK_NTTIME(stinfo.all_info.out.access_time,
851 finfo.all_info.out.access_time);
852 CHECK_NTTIME(stinfo.all_info.out.write_time,
853 finfo.all_info.out.write_time);
854 CHECK_NTTIME(stinfo.all_info.out.change_time,
855 finfo.all_info.out.change_time);
857 CHECK_VALUE(stinfo.all_info.out.attrib,
858 finfo.all_info.out.attrib);
859 CHECK_VALUE(stinfo.all_info.out.size,
860 finfo.all_info.out.size);
861 CHECK_VALUE(stinfo.all_info.out.delete_pending,
862 finfo.all_info.out.delete_pending);
863 CHECK_VALUE(stinfo.all_info.out.directory,
864 finfo.all_info.out.directory);
865 CHECK_VALUE(stinfo.all_info.out.ea_size,
866 finfo.all_info.out.ea_size);
868 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
869 stinfo.generic.in.file.fnum = fnum1;
870 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
871 CHECK_STATUS(status, NT_STATUS_OK);
872 if (!torture_setting_bool(tctx, "samba3", false)) {
873 CHECK_STR(stinfo.name_info.out.fname.s, rpath);
876 write_time = finfo.all_info.out.write_time;
877 write_time += i*1000000;
878 write_time /= 1000000;
879 write_time *= 1000000;
881 ZERO_STRUCT(sinfo);
882 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
883 sinfo.basic_info.in.file.fnum = fnum1;
884 sinfo.basic_info.in.write_time = write_time;
885 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
886 status = smb_raw_setfileinfo(cli->tree, &sinfo);
887 CHECK_STATUS(status, NT_STATUS_OK);
889 stream_size = i*8192;
891 ZERO_STRUCT(sinfo);
892 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
893 sinfo.end_of_file_info.in.file.fnum = fnum1;
894 sinfo.end_of_file_info.in.size = stream_size;
895 status = smb_raw_setfileinfo(cli->tree, &sinfo);
896 CHECK_STATUS(status, NT_STATUS_OK);
898 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
899 stinfo.generic.in.file.fnum = fnum1;
900 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
901 CHECK_STATUS(status, NT_STATUS_OK);
902 if (!torture_setting_bool(tctx, "samba3", false)) {
903 CHECK_NTTIME(stinfo.all_info.out.write_time,
904 write_time);
905 CHECK_VALUE(stinfo.all_info.out.attrib,
906 finfo.all_info.out.attrib);
908 CHECK_VALUE(stinfo.all_info.out.size,
909 stream_size);
910 CHECK_VALUE(stinfo.all_info.out.delete_pending,
911 finfo.all_info.out.delete_pending);
912 CHECK_VALUE(stinfo.all_info.out.directory,
913 finfo.all_info.out.directory);
914 CHECK_VALUE(stinfo.all_info.out.ea_size,
915 finfo.all_info.out.ea_size);
917 ret &= check_stream_list(tctx, cli, fname, 4, four);
919 smbcli_close(cli->tree, fnum1);
920 talloc_free(path);
923 printf("(%s): testing stream renames\n", __location__);
924 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
925 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
926 SEC_FILE_WRITE_ATTRIBUTE |
927 SEC_RIGHTS_FILE_ALL;
928 io.ntcreatex.in.fname = snamer1;
929 status = smb_raw_open(cli->tree, tctx, &io);
930 CHECK_STATUS(status, NT_STATUS_OK);
931 fnum1 = io.ntcreatex.out.file.fnum;
933 ret &= check_stream_list(tctx, cli, fname, 5, five1);
935 ZERO_STRUCT(sinfo);
936 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
937 sinfo.rename_information.in.file.fnum = fnum1;
938 sinfo.rename_information.in.overwrite = true;
939 sinfo.rename_information.in.root_fid = 0;
940 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
941 status = smb_raw_setfileinfo(cli->tree, &sinfo);
942 CHECK_STATUS(status, NT_STATUS_OK);
944 ret &= check_stream_list(tctx, cli, fname, 5, five2);
946 ZERO_STRUCT(sinfo);
947 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
948 sinfo.rename_information.in.file.fnum = fnum1;
949 sinfo.rename_information.in.overwrite = false;
950 sinfo.rename_information.in.root_fid = 0;
951 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
952 status = smb_raw_setfileinfo(cli->tree, &sinfo);
953 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
955 ret &= check_stream_list(tctx, cli, fname, 5, five2);
957 ZERO_STRUCT(sinfo);
958 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
959 sinfo.rename_information.in.file.fnum = fnum1;
960 sinfo.rename_information.in.overwrite = true;
961 sinfo.rename_information.in.root_fid = 0;
962 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
963 status = smb_raw_setfileinfo(cli->tree, &sinfo);
964 if (torture_setting_bool(tctx, "samba4", false) ||
965 torture_setting_bool(tctx, "samba3", false)) {
966 /* why should this rename be considered invalid?? */
967 CHECK_STATUS(status, NT_STATUS_OK);
968 ret &= check_stream_list(tctx, cli, fname, 4, four);
969 } else {
970 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
971 ret &= check_stream_list(tctx, cli, fname, 5, five2);
975 /* TODO: we need to test more rename combinations */
977 done:
978 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
979 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
980 if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
981 status = smbcli_unlink(cli->tree, fname);
982 smbcli_deltree(cli->tree, BASEDIR);
983 return ret;
987 test stream names
989 static bool test_stream_names2(struct torture_context *tctx,
990 struct smbcli_state *cli)
992 NTSTATUS status;
993 union smb_open io;
994 const char *fname = BASEDIR "\\stream_names2.txt";
995 bool ret = true;
996 int fnum1 = -1;
997 uint8_t i;
999 if (!torture_setup_dir(cli, BASEDIR)) {
1000 return false;
1003 printf("(%s) testing stream names\n", __location__);
1004 io.generic.level = RAW_OPEN_NTCREATEX;
1005 io.ntcreatex.in.root_fid.fnum = 0;
1006 io.ntcreatex.in.flags = 0;
1007 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1008 io.ntcreatex.in.create_options = 0;
1009 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1010 io.ntcreatex.in.share_access = 0;
1011 io.ntcreatex.in.alloc_size = 0;
1012 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1013 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1014 io.ntcreatex.in.security_flags = 0;
1015 io.ntcreatex.in.fname = fname;
1016 status = smb_raw_open(cli->tree, tctx, &io);
1017 CHECK_STATUS(status, NT_STATUS_OK);
1018 fnum1 = io.ntcreatex.out.file.fnum;
1020 for (i=0x01; i < 0x7F; i++) {
1021 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1022 fname, i, i);
1023 NTSTATUS expected;
1025 switch (i) {
1026 case '/':/*0x2F*/
1027 case ':':/*0x3A*/
1028 case '\\':/*0x5C*/
1029 expected = NT_STATUS_OBJECT_NAME_INVALID;
1030 break;
1031 default:
1032 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1033 break;
1037 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1038 io.ntcreatex.in.fname = path;
1039 status = smb_raw_open(cli->tree, tctx, &io);
1040 if (!NT_STATUS_EQUAL(status, expected)) {
1041 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1042 __location__, fname, isprint(i)?(char)i:' ', i,
1043 isprint(i)?"":" (not printable)",
1044 nt_errstr(expected));
1046 CHECK_STATUS(status, expected);
1048 talloc_free(path);
1051 done:
1052 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1053 status = smbcli_unlink(cli->tree, fname);
1054 smbcli_deltree(cli->tree, BASEDIR);
1055 return ret;
1058 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1059 check_fnum = true; \
1060 call_name = #call; \
1061 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1062 sfinfo.generic.in.file.fnum = fnum; \
1063 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1064 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1065 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1066 nt_errstr(status), nt_errstr(rightstatus)); \
1067 ret = false; \
1069 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1070 finfo1.generic.in.file.fnum = fnum; \
1071 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1072 if (!NT_STATUS_IS_OK(status2)) { \
1073 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1074 ret = false; \
1075 }} while (0)
1078 test stream renames
1080 static bool test_stream_rename(struct torture_context *tctx,
1081 struct smbcli_state *cli)
1083 NTSTATUS status, status2;
1084 union smb_open io;
1085 const char *fname = BASEDIR "\\stream_rename.txt";
1086 const char *sname1, *sname2;
1087 union smb_fileinfo finfo1;
1088 union smb_setfileinfo sfinfo;
1089 bool ret = true;
1090 int fnum = -1;
1091 bool check_fnum;
1092 const char *call_name;
1094 if (!torture_setup_dir(cli, BASEDIR)) {
1095 return false;
1098 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1099 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1101 printf("(%s) testing stream renames\n", __location__);
1102 io.generic.level = RAW_OPEN_NTCREATEX;
1103 io.ntcreatex.in.root_fid.fnum = 0;
1104 io.ntcreatex.in.flags = 0;
1105 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1106 SEC_FILE_WRITE_ATTRIBUTE |
1107 SEC_RIGHTS_FILE_ALL;
1108 io.ntcreatex.in.create_options = 0;
1109 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1110 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1111 io.ntcreatex.in.alloc_size = 0;
1112 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1113 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1114 io.ntcreatex.in.security_flags = 0;
1115 io.ntcreatex.in.fname = sname1;
1117 /* Create two streams. */
1118 status = smb_raw_open(cli->tree, tctx, &io);
1119 CHECK_STATUS(status, NT_STATUS_OK);
1120 fnum = io.ntcreatex.out.file.fnum;
1121 if (fnum != -1) smbcli_close(cli->tree, fnum);
1123 io.ntcreatex.in.fname = sname2;
1124 status = smb_raw_open(cli->tree, tctx, &io);
1125 CHECK_STATUS(status, NT_STATUS_OK);
1126 fnum = io.ntcreatex.out.file.fnum;
1128 if (fnum != -1) smbcli_close(cli->tree, fnum);
1131 * Open the second stream.
1134 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1135 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1136 status = smb_raw_open(cli->tree, tctx, &io);
1137 CHECK_STATUS(status, NT_STATUS_OK);
1138 fnum = io.ntcreatex.out.file.fnum;
1141 * Now rename the second stream onto the first.
1144 ZERO_STRUCT(sfinfo);
1146 sfinfo.rename_information.in.overwrite = 1;
1147 sfinfo.rename_information.in.root_fid = 0;
1148 sfinfo.rename_information.in.new_name = ":Stream One";
1149 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1151 done:
1152 if (fnum != -1) smbcli_close(cli->tree, fnum);
1153 status = smbcli_unlink(cli->tree, fname);
1154 smbcli_deltree(cli->tree, BASEDIR);
1155 return ret;
1158 static bool test_stream_rename2(struct torture_context *tctx,
1159 struct smbcli_state *cli)
1161 NTSTATUS status;
1162 union smb_open io;
1163 const char *fname1 = BASEDIR "\\stream.txt";
1164 const char *fname2 = BASEDIR "\\stream2.txt";
1165 const char *stream_name1 = ":Stream One:$DATA";
1166 const char *stream_name2 = ":Stream Two:$DATA";
1167 const char *stream_name_default = "::$DATA";
1168 const char *sname1;
1169 const char *sname2;
1170 bool ret = true;
1171 int fnum = -1;
1172 union smb_setfileinfo sinfo;
1173 union smb_rename rio;
1175 if (!torture_setup_dir(cli, BASEDIR)) {
1176 return false;
1179 sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1180 sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1182 io.generic.level = RAW_OPEN_NTCREATEX;
1183 io.ntcreatex.in.root_fid.fnum = 0;
1184 io.ntcreatex.in.flags = 0;
1185 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1186 SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1187 io.ntcreatex.in.create_options = 0;
1188 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1189 io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1190 NTCREATEX_SHARE_ACCESS_WRITE |
1191 NTCREATEX_SHARE_ACCESS_DELETE);
1192 io.ntcreatex.in.alloc_size = 0;
1193 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1194 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1195 io.ntcreatex.in.security_flags = 0;
1196 io.ntcreatex.in.fname = sname1;
1198 /* Open/create new stream. */
1199 status = smb_raw_open(cli->tree, tctx, &io);
1200 CHECK_STATUS(status, NT_STATUS_OK);
1202 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1205 * Check raw rename with <base>:<stream>.
1207 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1208 __location__);
1209 rio.generic.level = RAW_RENAME_NTRENAME;
1210 rio.ntrename.in.old_name = sname1;
1211 rio.ntrename.in.new_name = sname2;
1212 rio.ntrename.in.attrib = 0;
1213 rio.ntrename.in.cluster_size = 0;
1214 rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1215 status = smb_raw_rename(cli->tree, &rio);
1216 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1219 * Check raw rename to the default stream using :<stream>.
1221 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1222 __location__);
1223 rio.ntrename.in.new_name = stream_name_default;
1224 status = smb_raw_rename(cli->tree, &rio);
1225 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1228 * Check raw rename using :<stream>.
1230 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1231 __location__);
1232 rio.ntrename.in.new_name = stream_name2;
1233 status = smb_raw_rename(cli->tree, &rio);
1234 CHECK_STATUS(status, NT_STATUS_OK);
1237 * Check raw rename of a stream to a file.
1239 printf("(%s) Checking NTRENAME of a stream to a file\n",
1240 __location__);
1241 rio.ntrename.in.old_name = sname2;
1242 rio.ntrename.in.new_name = fname2;
1243 status = smb_raw_rename(cli->tree, &rio);
1244 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1247 * Check raw rename of a file to a stream.
1249 printf("(%s) Checking NTRENAME of a file to a stream\n",
1250 __location__);
1252 /* Create the file. */
1253 io.ntcreatex.in.fname = fname2;
1254 status = smb_raw_open(cli->tree, tctx, &io);
1255 CHECK_STATUS(status, NT_STATUS_OK);
1256 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1258 /* Try the rename. */
1259 rio.ntrename.in.old_name = fname2;
1260 rio.ntrename.in.new_name = sname1;
1261 status = smb_raw_rename(cli->tree, &rio);
1262 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1265 * Reopen the stream for trans2 renames.
1267 io.ntcreatex.in.fname = sname2;
1268 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1269 status = smb_raw_open(cli->tree, tctx, &io);
1270 CHECK_STATUS(status, NT_STATUS_OK);
1271 fnum = io.ntcreatex.out.file.fnum;
1274 * Check trans2 rename of a stream using :<stream>.
1276 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1277 __location__);
1278 ZERO_STRUCT(sinfo);
1279 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1280 sinfo.rename_information.in.file.fnum = fnum;
1281 sinfo.rename_information.in.overwrite = 1;
1282 sinfo.rename_information.in.root_fid = 0;
1283 sinfo.rename_information.in.new_name = stream_name1;
1284 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1285 CHECK_STATUS(status, NT_STATUS_OK);
1288 * Check trans2 rename of an overwriting stream using :<stream>.
1290 printf("(%s) Checking trans2 rename of an overwriting stream using "
1291 ":<stream>\n", __location__);
1293 /* Create second stream. */
1294 io.ntcreatex.in.fname = sname2;
1295 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1296 status = smb_raw_open(cli->tree, tctx, &io);
1297 CHECK_STATUS(status, NT_STATUS_OK);
1298 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1300 /* Rename the first stream onto the second. */
1301 sinfo.rename_information.in.file.fnum = fnum;
1302 sinfo.rename_information.in.new_name = stream_name2;
1303 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1304 CHECK_STATUS(status, NT_STATUS_OK);
1306 smbcli_close(cli->tree, fnum);
1309 * Reopen the stream with the new name.
1311 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1312 io.ntcreatex.in.fname = sname2;
1313 status = smb_raw_open(cli->tree, tctx, &io);
1314 CHECK_STATUS(status, NT_STATUS_OK);
1315 fnum = io.ntcreatex.out.file.fnum;
1318 * Check trans2 rename of a stream using <base>:<stream>.
1320 printf("(%s) Checking trans2 rename of a stream using "
1321 "<base>:<stream>\n", __location__);
1322 sinfo.rename_information.in.file.fnum = fnum;
1323 sinfo.rename_information.in.new_name = sname1;
1324 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1325 CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1328 * Samba3 doesn't currently support renaming a stream to the default
1329 * stream. This test does pass on windows.
1331 if (torture_setting_bool(tctx, "samba3", false) ||
1332 torture_setting_bool(tctx, "samba4", false)) {
1333 goto done;
1337 * Check trans2 rename to the default stream using :<stream>.
1339 printf("(%s) Checking trans2 rename to defaualt stream using "
1340 ":<stream>\n", __location__);
1341 sinfo.rename_information.in.file.fnum = fnum;
1342 sinfo.rename_information.in.new_name = stream_name_default;
1343 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1344 CHECK_STATUS(status, NT_STATUS_OK);
1346 smbcli_close(cli->tree, fnum);
1348 done:
1349 smbcli_close(cli->tree, fnum);
1350 status = smbcli_unlink(cli->tree, fname1);
1351 status = smbcli_unlink(cli->tree, fname2);
1352 smbcli_deltree(cli->tree, BASEDIR);
1353 return ret;
1357 test stream renames
1359 static bool test_stream_rename3(struct torture_context *tctx,
1360 struct smbcli_state *cli)
1362 NTSTATUS status, status2;
1363 union smb_open io;
1364 const char *fname = BASEDIR "\\stream_rename.txt";
1365 const char *sname1, *sname2;
1366 union smb_fileinfo finfo1;
1367 union smb_setfileinfo sfinfo;
1368 bool ret = true;
1369 int fnum = -1;
1370 int fnum2 = -1;
1371 bool check_fnum;
1372 const char *call_name;
1374 if (!torture_setup_dir(cli, BASEDIR)) {
1375 return false;
1378 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1379 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1381 printf("(%s) testing stream renames\n", __location__);
1382 io.generic.level = RAW_OPEN_NTCREATEX;
1383 io.ntcreatex.in.root_fid.fnum = 0;
1384 io.ntcreatex.in.flags = 0;
1385 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1386 SEC_FILE_WRITE_ATTRIBUTE |
1387 SEC_RIGHTS_FILE_ALL;
1388 io.ntcreatex.in.create_options = 0;
1389 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1390 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1391 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1392 io.ntcreatex.in.alloc_size = 0;
1393 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1394 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1395 io.ntcreatex.in.security_flags = 0;
1396 io.ntcreatex.in.fname = sname1;
1398 /* Create two streams. */
1399 status = smb_raw_open(cli->tree, tctx, &io);
1400 CHECK_STATUS(status, NT_STATUS_OK);
1401 fnum = io.ntcreatex.out.file.fnum;
1402 if (fnum != -1) smbcli_close(cli->tree, fnum);
1404 io.ntcreatex.in.fname = sname2;
1405 status = smb_raw_open(cli->tree, tctx, &io);
1406 CHECK_STATUS(status, NT_STATUS_OK);
1407 fnum = io.ntcreatex.out.file.fnum;
1409 if (fnum != -1) smbcli_close(cli->tree, fnum);
1411 /* open the second stream. */
1412 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1413 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1414 status = smb_raw_open(cli->tree, tctx, &io);
1415 CHECK_STATUS(status, NT_STATUS_OK);
1416 fnum = io.ntcreatex.out.file.fnum;
1418 /* Keep a handle to the first stream open. */
1419 io.ntcreatex.in.fname = sname1;
1420 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1421 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1422 status = smb_raw_open(cli->tree, tctx, &io);
1423 CHECK_STATUS(status, NT_STATUS_OK);
1424 fnum2 = io.ntcreatex.out.file.fnum;
1426 ZERO_STRUCT(sfinfo);
1427 sfinfo.rename_information.in.overwrite = 1;
1428 sfinfo.rename_information.in.root_fid = 0;
1429 sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1430 if (torture_setting_bool(tctx, "samba4", false) ||
1431 torture_setting_bool(tctx, "samba3", false)) {
1432 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1433 } else {
1434 CHECK_CALL_FNUM(RENAME_INFORMATION,
1435 NT_STATUS_INVALID_PARAMETER);
1439 done:
1440 if (fnum != -1) smbcli_close(cli->tree, fnum);
1441 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1442 status = smbcli_unlink(cli->tree, fname);
1443 smbcli_deltree(cli->tree, BASEDIR);
1444 return ret;
1447 static bool create_file_with_stream(struct torture_context *tctx,
1448 struct smbcli_state *cli,
1449 const char *stream)
1451 NTSTATUS status;
1452 bool ret = true;
1453 union smb_open io;
1455 /* Create a file with a stream */
1456 io.generic.level = RAW_OPEN_NTCREATEX;
1457 io.ntcreatex.in.root_fid.fnum = 0;
1458 io.ntcreatex.in.flags = 0;
1459 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1460 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1461 io.ntcreatex.in.create_options = 0;
1462 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1463 io.ntcreatex.in.share_access = 0;
1464 io.ntcreatex.in.alloc_size = 0;
1465 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1466 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1467 io.ntcreatex.in.security_flags = 0;
1468 io.ntcreatex.in.fname = stream;
1470 status = smb_raw_open(cli->tree, tctx, &io);
1471 CHECK_STATUS(status, NT_STATUS_OK);
1473 done:
1474 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1475 return ret;
1478 /* Test how streams interact with create dispositions */
1479 static bool test_stream_create_disposition(struct torture_context *tctx,
1480 struct smbcli_state *cli)
1482 NTSTATUS status;
1483 union smb_open io;
1484 const char *fname = BASEDIR "\\stream.txt";
1485 const char *stream = "Stream One:$DATA";
1486 const char *fname_stream;
1487 const char *default_stream_name = "::$DATA";
1488 const char *stream_list[2];
1489 bool ret = false;
1490 int fnum = -1;
1492 if (!torture_setup_dir(cli, BASEDIR)) {
1493 return false;
1496 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1498 stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1499 stream_list[1] = default_stream_name;
1501 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1502 goto done;
1505 /* Open the base file with OPEN */
1506 io.generic.level = RAW_OPEN_NTCREATEX;
1507 io.ntcreatex.in.root_fid.fnum = 0;
1508 io.ntcreatex.in.flags = 0;
1509 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1510 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1511 io.ntcreatex.in.create_options = 0;
1512 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1513 io.ntcreatex.in.share_access = 0;
1514 io.ntcreatex.in.alloc_size = 0;
1515 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1516 io.ntcreatex.in.security_flags = 0;
1517 io.ntcreatex.in.fname = fname;
1520 * check ntcreatex open: sanity check
1522 printf("(%s) Checking ntcreatex disp: open\n", __location__);
1523 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1524 status = smb_raw_open(cli->tree, tctx, &io);
1525 CHECK_STATUS(status, NT_STATUS_OK);
1526 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1527 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1528 goto done;
1532 * check ntcreatex overwrite
1534 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1535 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1536 status = smb_raw_open(cli->tree, tctx, &io);
1537 CHECK_STATUS(status, NT_STATUS_OK);
1538 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1539 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1540 goto done;
1544 * check ntcreatex overwrite_if
1546 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1547 smbcli_unlink(cli->tree, fname);
1548 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1549 goto done;
1552 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1553 status = smb_raw_open(cli->tree, tctx, &io);
1554 CHECK_STATUS(status, NT_STATUS_OK);
1555 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1556 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1557 goto done;
1561 * check ntcreatex supersede
1563 printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1564 smbcli_unlink(cli->tree, fname);
1565 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1566 goto done;
1569 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1570 status = smb_raw_open(cli->tree, tctx, &io);
1571 CHECK_STATUS(status, NT_STATUS_OK);
1572 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1573 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1574 goto done;
1578 * check ntcreatex overwrite_if on a stream.
1580 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1581 __location__);
1582 smbcli_unlink(cli->tree, fname);
1583 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1584 goto done;
1587 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1588 io.ntcreatex.in.fname = fname_stream;
1589 status = smb_raw_open(cli->tree, tctx, &io);
1590 CHECK_STATUS(status, NT_STATUS_OK);
1591 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1592 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1593 goto done;
1597 * check openx overwrite_if
1599 printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1600 smbcli_unlink(cli->tree, fname);
1601 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1602 goto done;
1605 io.openx.level = RAW_OPEN_OPENX;
1606 io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1607 io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1608 io.openx.in.search_attrs = 0;
1609 io.openx.in.file_attrs = 0;
1610 io.openx.in.write_time = 0;
1611 io.openx.in.size = 1024*1024;
1612 io.openx.in.timeout = 0;
1613 io.openx.in.fname = fname;
1615 io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1616 status = smb_raw_open(cli->tree, tctx, &io);
1617 CHECK_STATUS(status, NT_STATUS_OK);
1618 smbcli_close(cli->tree, io.openx.out.file.fnum);
1619 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1620 goto done;
1623 ret = true;
1625 done:
1626 smbcli_close(cli->tree, fnum);
1627 smbcli_unlink(cli->tree, fname);
1628 smbcli_deltree(cli->tree, BASEDIR);
1629 return ret;
1632 #if 0
1633 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1634 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1635 struct smbcli_state *cli)
1637 #define LONG_STREAM_SIZE 2
1638 char *lstream_name;
1639 const char *fname = BASEDIR "\\stream.txt";
1640 const char *fname_stream;
1641 NTSTATUS status;
1642 bool ret = true;
1643 int i;
1644 union smb_fileinfo finfo;
1646 if (!torture_setup_dir(cli, BASEDIR)) {
1647 return false;
1650 lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1652 for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1653 lstream_name[i] = (char)('a' + i%26);
1655 lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1657 torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1658 for (i = 0; i < 10000; i++) {
1659 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1660 lstream_name, i);
1661 ret = create_file_with_stream(tctx, cli, fname_stream);
1662 if (!ret) {
1663 goto done;
1667 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1668 finfo.generic.in.file.path = fname;
1670 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1671 CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1673 done:
1674 smbcli_unlink(cli->tree, fname);
1675 smbcli_deltree(cli->tree, BASEDIR);
1676 return ret;
1678 #endif
1680 /* Test the effect of setting attributes on a stream. */
1681 static bool test_stream_attributes(struct torture_context *tctx,
1682 struct smbcli_state *cli)
1684 bool ret = true;
1685 NTSTATUS status;
1686 union smb_open io;
1687 const char *fname = BASEDIR "\\stream_attr.txt";
1688 const char *stream = "Stream One:$DATA";
1689 const char *fname_stream;
1690 int fnum = -1;
1691 union smb_fileinfo finfo;
1692 union smb_setfileinfo sfinfo;
1693 time_t basetime = (time(NULL) - 86400) & ~1;
1695 if (!torture_setup_dir(cli, BASEDIR)) {
1696 return false;
1699 torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1701 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1703 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1704 ret = create_file_with_stream(tctx, cli, fname_stream);
1705 if (!ret) {
1706 goto done;
1709 ZERO_STRUCT(finfo);
1710 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1711 finfo.generic.in.file.path = fname;
1712 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1713 CHECK_STATUS(status, NT_STATUS_OK);
1715 if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1716 printf("(%s) Incorrect attrib %x - should be %x\n", \
1717 __location__, (unsigned int)finfo.basic_info.out.attrib,
1718 (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1719 ret = false;
1720 goto done;
1723 /* Now open the stream name. */
1725 io.generic.level = RAW_OPEN_NTCREATEX;
1726 io.ntcreatex.in.root_fid.fnum = 0;
1727 io.ntcreatex.in.flags = 0;
1728 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1729 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1730 io.ntcreatex.in.create_options = 0;
1731 io.ntcreatex.in.file_attr = 0;
1732 io.ntcreatex.in.share_access = 0;
1733 io.ntcreatex.in.alloc_size = 0;
1734 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1735 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1736 io.ntcreatex.in.security_flags = 0;
1737 io.ntcreatex.in.fname = fname_stream;
1739 status = smb_raw_open(cli->tree, tctx, &io);
1740 CHECK_STATUS(status, NT_STATUS_OK);
1742 fnum = io.ntcreatex.out.file.fnum;
1744 /* Change the attributes + time on the stream fnum. */
1745 ZERO_STRUCT(sfinfo);
1746 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1747 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1749 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1750 sfinfo.generic.in.file.fnum = fnum;
1751 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1752 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1753 printf("(%s) %s - %s (should be %s)\n", __location__, "SETATTR",
1754 nt_errstr(status), nt_errstr(NT_STATUS_OK));
1755 ret = false;
1756 goto done;
1759 smbcli_close(cli->tree, fnum);
1760 fnum = -1;
1762 ZERO_STRUCT(finfo);
1763 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1764 finfo.generic.in.file.path = fname;
1765 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1766 if (!NT_STATUS_IS_OK(status)) {
1767 printf("(%s) %s pathinfo - %s\n", __location__, "SETATTRE", nt_errstr(status));
1768 ret = false;
1769 goto done;
1772 if (finfo.all_info.out.attrib != FILE_ATTRIBUTE_READONLY) {
1773 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1774 __location__,
1775 (unsigned int)finfo.all_info.out.attrib,
1776 (unsigned int)FILE_ATTRIBUTE_READONLY);
1777 ret = false;
1778 goto done;
1781 if (nt_time_to_unix(finfo.all_info.out.write_time) != basetime) {
1782 printf("(%s) time incorrect.\n",
1783 __location__);
1784 ret = false;
1785 goto done;
1788 done:
1790 if (fnum != -1) {
1791 smbcli_close(cli->tree, fnum);
1793 smbcli_unlink(cli->tree, fname);
1794 smbcli_deltree(cli->tree, BASEDIR);
1795 return ret;
1799 * A rough approximation of how a windows client creates the streams for use
1800 * in the summary tab.
1802 static bool test_stream_summary_tab(struct torture_context *tctx,
1803 struct smbcli_state *cli)
1805 bool ret = true;
1806 NTSTATUS status;
1807 union smb_open io;
1808 const char *fname = BASEDIR "\\stream_summary.txt";
1809 const char *stream = ":\005SummaryInformation:$DATA";
1810 const char *fname_stream = NULL;
1811 const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1812 const char *fname_tmp_stream = NULL;
1813 int fnum = -1;
1814 union smb_fileinfo finfo;
1815 union smb_rename rio;
1816 ssize_t retsize;
1818 if (!torture_setup_dir(cli, BASEDIR)) {
1819 return false;
1822 fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1823 fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1824 tmp_stream);
1826 /* Create summary info stream */
1827 ret = create_file_with_stream(tctx, cli, fname_stream);
1828 if (!ret) {
1829 goto done;
1832 /* Create summary info tmp update stream */
1833 ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1834 if (!ret) {
1835 goto done;
1838 /* Open tmp stream and write to it */
1839 io.generic.level = RAW_OPEN_NTCREATEX;
1840 io.ntcreatex.in.root_fid.fnum = 0;
1841 io.ntcreatex.in.flags = 0;
1842 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1843 io.ntcreatex.in.create_options = 0;
1844 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1845 io.ntcreatex.in.share_access = 0;
1846 io.ntcreatex.in.alloc_size = 0;
1847 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1848 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1849 io.ntcreatex.in.security_flags = 0;
1850 io.ntcreatex.in.fname = fname_tmp_stream;
1852 status = smb_raw_open(cli->tree, tctx, &io);
1853 CHECK_STATUS(status, NT_STATUS_OK);
1854 fnum = io.ntcreatex.out.file.fnum;
1856 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1857 CHECK_VALUE(retsize, 9);
1859 /* close the tmp stream. */
1860 smbcli_close(cli->tree, fnum);
1861 fnum = -1;
1863 /* Delete the current stream */
1864 smbcli_unlink(cli->tree, fname_stream);
1866 /* Do the rename. */
1867 rio.generic.level = RAW_RENAME_RENAME;
1868 rio.rename.in.pattern1 = fname_tmp_stream;
1869 rio.rename.in.pattern2 = stream;
1870 rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1871 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1872 status = smb_raw_rename(cli->tree, &rio);
1873 CHECK_STATUS(status, NT_STATUS_OK);
1875 /* Try to open the tmp stream that we just renamed away. */
1876 status = smb_raw_open(cli->tree, tctx, &io);
1877 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1879 /* Query the base file to make sure it's still there. */
1880 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1881 finfo.generic.in.file.path = fname;
1883 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1884 CHECK_STATUS(status, NT_STATUS_OK);
1886 done:
1888 if (fnum != -1) {
1889 smbcli_close(cli->tree, fnum);
1891 smbcli_unlink(cli->tree, fname);
1893 smbcli_deltree(cli->tree, BASEDIR);
1894 return ret;
1898 basic testing of streams calls
1900 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
1902 struct torture_suite *suite = torture_suite_create(tctx, "streams");
1904 torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
1905 torture_suite_add_1smb_test(suite, "io", test_stream_io);
1906 torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
1907 torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
1908 torture_suite_add_1smb_test(suite, "names", test_stream_names);
1909 torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
1910 torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
1911 torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
1912 torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
1913 torture_suite_add_1smb_test(suite, "createdisp",
1914 test_stream_create_disposition);
1915 torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
1916 torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
1918 #if 0
1919 torture_suite_add_1smb_test(suite, "LARGESTREAMINFO",
1920 test_stream_large_streaminfo);
1921 #endif
1923 return suite;