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/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
29 #include "system/filesys.h"
30 #include "system/locale.h"
31 #include "lib/util/tsort.h"
33 #define DNAME "teststreams"
35 #define CHECK_STATUS(status, correct) do { \
36 if (!NT_STATUS_EQUAL(status, correct)) { \
37 torture_result(tctx, TORTURE_FAIL, \
38 "(%s) Incorrect status %s - should be %s\n", \
39 __location__, nt_errstr(status), nt_errstr(correct)); \
44 #define CHECK_VALUE(v, correct) do { \
45 if ((v) != (correct)) { \
46 torture_result(tctx, TORTURE_FAIL, \
47 "(%s) Incorrect value %s=%d - should be %d\n", \
48 __location__, #v, (int)v, (int)correct); \
52 #define CHECK_NTTIME(v, correct) do { \
53 if ((v) != (correct)) { \
54 torture_result(tctx, TORTURE_FAIL, \
55 "(%s) Incorrect value %s=%llu - should be %llu\n", \
56 __location__, #v, (unsigned long long)v, \
57 (unsigned long long)correct); \
61 #define CHECK_STR(v, correct) do { \
63 if ((v) && !(correct)) { \
65 } else if (!(v) && (correct)) { \
67 } else if (!(v) && !(correct)) { \
69 } else if (strcmp((v), (correct)) == 0) { \
75 torture_result(tctx, TORTURE_FAIL, \
76 "(%s) Incorrect value %s='%s' - " \
78 __location__, #v, (v)?(v):"NULL", \
79 (correct)?(correct):"NULL"); \
84 static int qsort_string(char * const *s1
, char * const *s2
)
86 return strcmp(*s1
, *s2
);
89 static int qsort_stream(const struct stream_struct
* s1
, const struct stream_struct
*s2
)
91 return strcmp(s1
->stream_name
.s
, s2
->stream_name
.s
);
94 static bool check_stream(struct smb2_tree
*tree
,
101 struct smb2_handle handle
;
102 struct smb2_create create
;
105 const char *full_name
;
107 full_name
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, sname
);
110 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
111 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
112 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
113 create
.in
.fname
= full_name
;
115 status
= smb2_create(tree
, mem_ctx
, &create
);
116 if (!NT_STATUS_IS_OK(status
)) {
120 torture_comment(mem_ctx
, "Unable to open stream %s\n",
126 handle
= create
.out
.file
.handle
;
133 r
.in
.file
.handle
= handle
;
134 r
.in
.length
= strlen(value
)+11;
137 status
= smb2_read(tree
, tree
, &r
);
139 if (!NT_STATUS_IS_OK(status
)) {
140 torture_comment(mem_ctx
, "(%s) Failed to read %lu bytes from "
141 "stream '%s'\n", location
, (long)strlen(value
), full_name
);
145 if (memcmp(r
.out
.data
.data
, value
, strlen(value
)) != 0) {
146 torture_comment(mem_ctx
, "(%s) Bad data in stream\n", location
);
150 smb2_util_close(tree
, handle
);
154 static bool check_stream_list(struct smb2_tree
*tree
,
155 struct torture_context
*tctx
,
159 struct smb2_handle h
)
161 union smb_fileinfo finfo
;
164 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
166 struct stream_struct
*stream_sort
;
169 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFORMATION
;
170 finfo
.generic
.in
.file
.handle
= h
;
172 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
173 if (!NT_STATUS_IS_OK(status
)) {
174 torture_comment(tctx
, "(%s) smb_raw_pathinfo failed: %s\n",
175 __location__
, nt_errstr(status
));
179 if (finfo
.stream_info
.out
.num_streams
!= num_exp
) {
180 torture_comment(tctx
, "(%s) expected %d streams, got %d\n",
181 __location__
, num_exp
, finfo
.stream_info
.out
.num_streams
);
190 exp_sort
= talloc_memdup(tmp_ctx
, exp
, num_exp
* sizeof(*exp
));
192 if (exp_sort
== NULL
) {
196 TYPESAFE_QSORT(exp_sort
, num_exp
, qsort_string
);
198 stream_sort
= talloc_memdup(tmp_ctx
, finfo
.stream_info
.out
.streams
,
199 finfo
.stream_info
.out
.num_streams
*
200 sizeof(*stream_sort
));
202 if (stream_sort
== NULL
) {
206 TYPESAFE_QSORT(stream_sort
, finfo
.stream_info
.out
.num_streams
, qsort_stream
);
208 for (i
=0; i
<num_exp
; i
++) {
209 if (strcmp(exp_sort
[i
], stream_sort
[i
].stream_name
.s
) != 0) {
210 torture_comment(tctx
,
211 "(%s) expected stream name %s, got %s\n",
212 __location__
, exp_sort
[i
],
213 stream_sort
[i
].stream_name
.s
);
220 talloc_free(tmp_ctx
);
225 static bool test_stream_dir(struct torture_context
*tctx
,
226 struct smb2_tree
*tree
)
228 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
231 const char *fname
= DNAME
"\\stream.txt";
234 const char *basedir_data
;
235 struct smb2_handle h
;
237 smb2_util_unlink(tree
, fname
);
238 smb2_deltree(tree
, DNAME
);
240 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
241 CHECK_STATUS(status
, NT_STATUS_OK
);
243 basedir_data
= talloc_asprintf(mem_ctx
, "%s::$DATA", DNAME
);
244 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
245 torture_comment(tctx
, "%s\n", sname1
);
247 torture_comment(tctx
, "(%s) opening non-existent directory stream\n",
249 ZERO_STRUCT(io
.smb2
);
250 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
251 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
252 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
253 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
254 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
255 io
.smb2
.in
.share_access
= 0;
256 io
.smb2
.in
.alloc_size
= 0;
257 io
.smb2
.in
.security_flags
= 0;
258 io
.smb2
.in
.fname
= sname1
;
259 io
.smb2
.in
.create_flags
= 0;
260 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
261 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
263 torture_comment(tctx
, "(%s) opening basedir stream\n", __location__
);
264 ZERO_STRUCT(io
.smb2
);
265 io
.smb2
.in
.create_flags
= 0;
266 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
267 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
268 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
269 io
.smb2
.in
.share_access
= 0;
270 io
.smb2
.in
.alloc_size
= 0;
271 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
272 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
273 io
.smb2
.in
.security_flags
= 0;
274 io
.smb2
.in
.fname
= basedir_data
;
275 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
276 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
278 torture_comment(tctx
, "(%s) opening basedir ::$DATA stream\n",
280 ZERO_STRUCT(io
.smb2
);
281 io
.smb2
.in
.create_flags
= 0x10;
282 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
283 io
.smb2
.in
.create_options
= 0;
284 io
.smb2
.in
.file_attributes
= 0;
285 io
.smb2
.in
.share_access
= 0;
286 io
.smb2
.in
.alloc_size
= 0;
287 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
288 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
289 io
.smb2
.in
.security_flags
= 0;
290 io
.smb2
.in
.fname
= basedir_data
;
291 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
292 CHECK_STATUS(status
, NT_STATUS_FILE_IS_A_DIRECTORY
);
294 torture_comment(tctx
, "(%s) list the streams on the basedir\n",
296 ret
&= check_stream_list(tree
, mem_ctx
, DNAME
, 0, NULL
, h
);
298 smb2_util_unlink(tree
, fname
);
299 smb2_deltree(tree
, DNAME
);
300 talloc_free(mem_ctx
);
305 static bool test_stream_io(struct torture_context
*tctx
,
306 struct smb2_tree
*tree
)
308 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
311 const char *fname
= DNAME
"\\stream.txt";
312 const char *sname1
, *sname2
;
314 struct smb2_handle h
, h2
;
316 const char *one
[] = { "::$DATA" };
317 const char *two
[] = { "::$DATA", ":Second Stream:$DATA" };
318 const char *three
[] = { "::$DATA", ":Stream One:$DATA",
319 ":Second Stream:$DATA" };
321 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
322 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
325 smb2_util_unlink(tree
, fname
);
326 smb2_deltree(tree
, DNAME
);
328 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
329 CHECK_STATUS(status
, NT_STATUS_OK
);
331 torture_comment(tctx
, "(%s) creating a stream on a non-existent file\n",
334 ZERO_STRUCT(io
.smb2
);
335 io
.smb2
.in
.create_flags
= 0;
336 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
337 io
.smb2
.in
.create_options
= 0;
338 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
339 io
.smb2
.in
.share_access
= 0;
340 io
.smb2
.in
.alloc_size
= 0;
341 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
342 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
343 io
.smb2
.in
.security_flags
= 0;
344 io
.smb2
.in
.fname
= sname1
;
345 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
346 CHECK_STATUS(status
, NT_STATUS_OK
);
347 h2
= io
.smb2
.out
.file
.handle
;
349 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
352 torture_comment(tctx
, "(%s) check that open of base file is allowed\n", __location__
);
353 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
354 io
.smb2
.in
.fname
= fname
;
355 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
356 CHECK_STATUS(status
, NT_STATUS_OK
);
357 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
359 torture_comment(tctx
, "(%s) writing to stream\n", __location__
);
360 status
= smb2_util_write(tree
, h2
, "test data", 0, 9);
361 CHECK_STATUS(status
, NT_STATUS_OK
);
363 smb2_util_close(tree
, h2
);
365 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
366 "Stream One", "test data");
368 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
369 io
.smb2
.in
.fname
= sname1
;
370 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
371 CHECK_STATUS(status
, NT_STATUS_OK
);
372 h2
= io
.smb2
.out
.file
.handle
;
374 torture_comment(tctx
, "(%s) modifying stream\n", __location__
);
375 status
= smb2_util_write(tree
, h2
, "MORE DATA ", 5, 10);
376 CHECK_STATUS(status
, NT_STATUS_OK
);
378 smb2_util_close(tree
, h2
);
380 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
381 "Stream One:$FOO", NULL
);
383 torture_comment(tctx
, "(%s) creating a stream2 on a existing file\n",
385 io
.smb2
.in
.fname
= sname2
;
386 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
387 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
388 CHECK_STATUS(status
, NT_STATUS_OK
);
389 h2
= io
.smb2
.out
.file
.handle
;
391 torture_comment(tctx
, "(%s) modifying stream\n", __location__
);
392 status
= smb2_util_write(tree
, h2
, "SECOND STREAM", 0, 13);
393 CHECK_STATUS(status
, NT_STATUS_OK
);
394 smb2_util_close(tree
, h2
);
396 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
397 "Stream One", "test MORE DATA ");
399 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
400 "Stream One:$DATA", "test MORE DATA ");
402 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
403 "Stream One:", NULL
);
405 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
406 "Second Stream", "SECOND STREAM");
408 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
409 "SECOND STREAM:$DATA", "SECOND STREAM");
410 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
411 "Second Stream:$DATA", "SECOND STREAM");
413 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
414 "Second Stream:", NULL
);
416 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
417 "Second Stream:$FOO", NULL
);
419 io
.smb2
.in
.fname
= sname2
;
420 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
421 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
422 CHECK_STATUS(status
, NT_STATUS_OK
);
423 h2
= io
.smb2
.out
.file
.handle
;
424 check_stream_list(tree
, tctx
, fname
, 3, three
, h2
);
426 smb2_util_close(tree
, h2
);
428 torture_comment(tctx
, "(%s) deleting stream\n", __location__
);
429 status
= smb2_util_unlink(tree
, sname1
);
430 CHECK_STATUS(status
, NT_STATUS_OK
);
432 io
.smb2
.in
.fname
= sname2
;
433 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
434 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
435 CHECK_STATUS(status
, NT_STATUS_OK
);
436 h2
= io
.smb2
.out
.file
.handle
;
437 check_stream_list(tree
, tctx
, fname
, 2, two
, h2
);
438 smb2_util_close(tree
, h2
);
440 torture_comment(tctx
, "(%s) delete a stream via delete-on-close\n",
442 io
.smb2
.in
.fname
= sname2
;
443 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
444 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
445 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
446 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
448 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
449 CHECK_STATUS(status
, NT_STATUS_OK
);
450 h2
= io
.smb2
.out
.file
.handle
;
452 smb2_util_close(tree
, h2
);
453 status
= smb2_util_unlink(tree
, sname2
);
454 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
456 io
.smb2
.in
.fname
= fname
;
457 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
458 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
459 h2
= io
.smb2
.out
.file
.handle
;
460 check_stream_list(tree
,tctx
, fname
, 1, one
, h2
);
461 smb2_util_close(tree
, h2
);
463 if (!torture_setting_bool(tctx
, "samba4", false)) {
464 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
465 io
.smb2
.in
.fname
= sname1
;
466 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
467 CHECK_STATUS(status
, NT_STATUS_OK
);
468 smb2_util_close(tree
, io
.ntcreatex
.out
.file
.handle
);
469 io
.smb2
.in
.fname
= sname2
;
470 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
471 CHECK_STATUS(status
, NT_STATUS_OK
);
472 smb2_util_close(tree
, io
.ntcreatex
.out
.file
.handle
);
473 torture_comment(tctx
, "(%s) deleting file\n", __location__
);
474 status
= smb2_util_unlink(tree
, fname
);
475 CHECK_STATUS(status
, NT_STATUS_OK
);
480 smb2_util_close(tree
, h2
);
481 smb2_deltree(tree
, DNAME
);
482 talloc_free(mem_ctx
);
488 test stream sharemodes
490 static bool test_stream_sharemodes(struct torture_context
*tctx
,
491 struct smb2_tree
*tree
)
493 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
496 const char *fname
= DNAME
"\\stream_share.txt";
497 const char *sname1
, *sname2
;
499 struct smb2_handle h
, h1
, h2
;
501 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
502 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
505 smb2_util_unlink(tree
, fname
);
506 smb2_deltree(tree
, DNAME
);
508 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
509 CHECK_STATUS(status
, NT_STATUS_OK
);
511 torture_comment(tctx
, "(%s) Testing stream share mode conflicts\n",
513 ZERO_STRUCT(io
.smb2
);
514 io
.generic
.level
= RAW_OPEN_SMB2
;
515 io
.smb2
.in
.create_flags
= 0;
516 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
517 io
.smb2
.in
.create_options
= 0;
518 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
519 io
.smb2
.in
.share_access
= 0;
520 io
.smb2
.in
.alloc_size
= 0;
521 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
522 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
523 io
.smb2
.in
.security_flags
= 0;
524 io
.smb2
.in
.fname
= sname1
;
526 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
527 CHECK_STATUS(status
, NT_STATUS_OK
);
528 h1
= io
.smb2
.out
.file
.handle
;
531 * A different stream does not give a sharing violation
534 io
.smb2
.in
.fname
= sname2
;
535 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
536 CHECK_STATUS(status
, NT_STATUS_OK
);
537 h2
= io
.smb2
.out
.file
.handle
;
540 * ... whereas the same stream does with unchanged access/share_access
544 io
.smb2
.in
.fname
= sname1
;
545 io
.smb2
.in
.create_disposition
= 0;
546 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
547 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
549 io
.smb2
.in
.fname
= sname2
;
550 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
551 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
554 smb2_util_close(tree
, h1
);
555 smb2_util_close(tree
, h2
);
556 status
= smb2_util_unlink(tree
, fname
);
557 smb2_deltree(tree
, DNAME
);
558 talloc_free(mem_ctx
);
564 * Test FILE_SHARE_DELETE on streams
566 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
567 * with SEC_STD_DELETE.
569 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
570 * be opened with SEC_STD_DELETE.
572 * A stream held open with FILE_SHARE_DELETE allows the file to be
573 * deleted. After the main file is deleted, access to the open file descriptor
574 * still works, but all name-based access to both the main file as well as the
575 * stream is denied with DELETE pending.
577 * This means, an open of the main file with SEC_STD_DELETE should walk all
578 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
579 * SHARING_VIOLATION, the main open fails.
581 * Closing the main file after delete_on_close has been set does not really
582 * unlink it but leaves the corresponding share mode entry with
583 * delete_on_close being set around until all streams are closed.
585 * Opening a stream must also look at the main file's share mode entry, look
586 * at the delete_on_close bit and potentially return DELETE_PENDING.
589 static bool test_stream_delete(struct torture_context
*tctx
,
590 struct smb2_tree
*tree
)
592 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
595 const char *fname
= DNAME
"\\stream_delete.txt";
598 struct smb2_handle h
, h1
;
601 if (torture_setting_bool(tctx
, "samba4", false)) {
602 torture_comment(tctx
, "Skipping test as samba4 is enabled\n");
606 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
609 smb2_util_unlink(tree
, fname
);
610 smb2_deltree(tree
, fname
);
611 smb2_deltree(tree
, DNAME
);
613 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
614 CHECK_STATUS(status
, NT_STATUS_OK
);
616 torture_comment(tctx
, "(%s) opening non-existent file stream\n",
618 ZERO_STRUCT(io
.smb2
);
619 io
.smb2
.in
.create_flags
= 0;
620 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
621 io
.smb2
.in
.create_options
= 0;
622 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
623 io
.smb2
.in
.share_access
= 0;
624 io
.smb2
.in
.alloc_size
= 0;
625 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
626 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
627 io
.smb2
.in
.security_flags
= 0;
628 io
.smb2
.in
.fname
= sname1
;
630 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
631 CHECK_STATUS(status
, NT_STATUS_OK
);
632 h1
= io
.smb2
.out
.file
.handle
;
634 status
= smb2_util_write(tree
, h1
, "test data", 0, 9);
635 CHECK_STATUS(status
, NT_STATUS_OK
);
638 * One stream opened without FILE_SHARE_DELETE prevents the main file
639 * to be deleted or even opened with DELETE access
642 status
= smb2_util_unlink(tree
, fname
);
643 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
645 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
646 io
.smb2
.in
.fname
= fname
;
647 io
.smb2
.in
.desired_access
= SEC_STD_DELETE
;
648 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
649 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
651 smb2_util_close(tree
, h1
);
654 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
657 io
.smb2
.in
.fname
= sname1
;
658 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
659 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
660 NTCREATEX_SHARE_ACCESS_READ
|
661 NTCREATEX_SHARE_ACCESS_WRITE
;
662 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
663 CHECK_STATUS(status
, NT_STATUS_OK
);
664 h1
= io
.smb2
.out
.file
.handle
;
666 status
= smb2_util_unlink(tree
, fname
);
667 CHECK_STATUS(status
, NT_STATUS_OK
);
670 * file access still works on the stream while the main file is closed
673 r
.in
.file
.handle
= h1
;
677 status
= smb2_read(tree
, tree
, &r
);
678 CHECK_STATUS(status
, NT_STATUS_OK
);
681 * name-based access to both the main file and the stream does not
682 * work anymore but gives DELETE_PENDING
685 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
686 io
.smb2
.in
.fname
= fname
;
687 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
688 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
691 * older S3 doesn't do this
694 io
.smb2
.in
.fname
= sname1
;
695 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
696 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
698 smb2_util_close(tree
, h1
);
701 * After closing the stream the file is really gone.
704 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
705 io
.smb2
.in
.fname
= fname
;
706 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
707 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
710 smb2_util_close(tree
, h1
);
711 smb2_util_unlink(tree
, fname
);
712 smb2_deltree(tree
, DNAME
);
713 talloc_free(mem_ctx
);
721 static bool test_stream_names(struct torture_context
*tctx
,
722 struct smb2_tree
*tree
)
724 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
727 union smb_fileinfo finfo
;
728 union smb_fileinfo stinfo
;
729 union smb_setfileinfo sinfo
;
730 const char *fname
= DNAME
"\\stream_names.txt";
731 const char *sname1
, *sname1b
, *sname1c
, *sname1d
;
732 const char *sname2
, *snamew
, *snamew2
;
733 const char *snamer1
, *snamer2
;
735 struct smb2_handle h
, h1
, h2
, h3
;
737 const char *four
[4] = {
739 ":\x05Stream\n One:$DATA",
740 ":MStream Two:$DATA",
743 const char *five1
[5] = {
745 ":\x05Stream\n One:$DATA",
746 ":BeforeRename:$DATA",
747 ":MStream Two:$DATA",
750 const char *five2
[5] = {
752 ":\x05Stream\n One:$DATA",
753 ":AfterRename:$DATA",
754 ":MStream Two:$DATA",
758 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "\x05Stream\n One");
759 sname1b
= talloc_asprintf(mem_ctx
, "%s:", sname1
);
760 sname1c
= talloc_asprintf(mem_ctx
, "%s:$FOO", sname1
);
761 sname1d
= talloc_asprintf(mem_ctx
, "%s:?D*a", sname1
);
762 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
, "MStream Two");
763 snamew
= talloc_asprintf(mem_ctx
, "%s:%s:$DATA", fname
, "?Stream*");
764 snamew2
= talloc_asprintf(mem_ctx
, "%s\\stream*:%s:$DATA", DNAME
,
766 snamer1
= talloc_asprintf(mem_ctx
, "%s:%s:$DATA", fname
,
768 snamer2
= talloc_asprintf(mem_ctx
, "%s:%s:$DATA", fname
, "AfterRename");
771 smb2_util_unlink(tree
, fname
);
772 smb2_deltree(tree
, fname
);
773 smb2_deltree(tree
, DNAME
);
775 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
776 CHECK_STATUS(status
, NT_STATUS_OK
);
778 torture_comment(tctx
, "(%s) testing stream names\n", __location__
);
779 ZERO_STRUCT(io
.smb2
);
780 io
.smb2
.in
.create_flags
= 0;
781 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
782 io
.smb2
.in
.create_options
= 0;
783 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
784 io
.smb2
.in
.share_access
= 0;
785 io
.smb2
.in
.alloc_size
= 0;
786 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
787 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
788 io
.smb2
.in
.security_flags
= 0;
789 io
.smb2
.in
.fname
= sname1
;
791 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
792 CHECK_STATUS(status
, NT_STATUS_OK
);
793 h1
= io
.smb2
.out
.file
.handle
;
796 * A different stream does not give a sharing violation
799 io
.smb2
.in
.fname
= sname2
;
800 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
801 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
802 CHECK_STATUS(status
, NT_STATUS_OK
);
803 h2
= io
.smb2
.out
.file
.handle
;
806 * ... whereas the same stream does with unchanged access/share_access
810 io
.smb2
.in
.fname
= sname1
;
811 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_SUPERSEDE
;
812 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
813 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
815 io
.smb2
.in
.fname
= sname1b
;
816 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
817 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
819 io
.smb2
.in
.fname
= sname1c
;
820 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
821 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
822 /* w2k returns INVALID_PARAMETER */
823 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
825 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
828 io
.smb2
.in
.fname
= sname1d
;
829 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
830 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
831 /* w2k returns INVALID_PARAMETER */
832 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
834 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
837 io
.smb2
.in
.fname
= sname2
;
838 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
839 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
841 io
.smb2
.in
.fname
= snamew
;
842 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
843 CHECK_STATUS(status
, NT_STATUS_OK
);
844 h3
= io
.smb2
.out
.file
.handle
;
846 io
.smb2
.in
.fname
= snamew2
;
847 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
848 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
850 io
.smb2
.in
.fname
= fname
;
851 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
852 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
853 CHECK_STATUS(status
, NT_STATUS_OK
);
854 ret
&= check_stream_list(tree
, tctx
, fname
, 4, four
,
855 io
.smb2
.out
.file
.handle
);
857 smb2_util_close(tree
, h1
);
858 smb2_util_close(tree
, h2
);
859 smb2_util_close(tree
, h3
);
861 if (torture_setting_bool(tctx
, "samba4", true)) {
865 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
866 finfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
867 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
868 CHECK_STATUS(status
, NT_STATUS_OK
);
869 ret
&= check_stream_list(tree
, tctx
, fname
, 4, four
,
870 io
.smb2
.out
.file
.handle
);
872 for (i
=0; i
< 4; i
++) {
874 uint64_t stream_size
;
875 char *path
= talloc_asprintf(tctx
, "%s%s",
878 char *rpath
= talloc_strdup(path
, path
);
879 char *p
= strrchr(rpath
, ':');
887 torture_comment(tctx
, "(%s): i[%u][%s]\n",
888 __location__
, i
,path
);
889 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
890 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
|
891 SEC_FILE_WRITE_ATTRIBUTE
|
893 io
.smb2
.in
.fname
= path
;
894 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
895 CHECK_STATUS(status
, NT_STATUS_OK
);
896 h1
= io
.smb2
.out
.file
.handle
;
898 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
899 finfo
.generic
.in
.file
.path
= fname
;
900 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
901 CHECK_STATUS(status
, NT_STATUS_OK
);
903 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
904 stinfo
.generic
.in
.file
.handle
= h1
;
905 status
= smb2_getinfo_file(tree
, mem_ctx
, &stinfo
);
906 CHECK_STATUS(status
, NT_STATUS_OK
);
907 if (!torture_setting_bool(tctx
, "samba3", false)) {
908 CHECK_NTTIME(stinfo
.all_info
.out
.create_time
,
909 finfo
.all_info
.out
.create_time
);
910 CHECK_NTTIME(stinfo
.all_info
.out
.access_time
,
911 finfo
.all_info
.out
.access_time
);
912 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
913 finfo
.all_info
.out
.write_time
);
914 CHECK_NTTIME(stinfo
.all_info
.out
.change_time
,
915 finfo
.all_info
.out
.change_time
);
917 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
918 finfo
.all_info
.out
.attrib
);
919 CHECK_VALUE(stinfo
.all_info
.out
.size
,
920 finfo
.all_info
.out
.size
);
921 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
922 finfo
.all_info
.out
.delete_pending
);
923 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
924 finfo
.all_info
.out
.directory
);
925 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
926 finfo
.all_info
.out
.ea_size
);
928 stinfo
.generic
.level
= RAW_FILEINFO_NAME_INFORMATION
;
929 stinfo
.generic
.in
.file
.handle
= h1
;
930 status
= smb2_getinfo_file(tree
, mem_ctx
, &stinfo
);
931 CHECK_STATUS(status
, NT_STATUS_OK
);
932 if (!torture_setting_bool(tctx
, "samba3", false)) {
933 CHECK_STR(rpath
, stinfo
.name_info
.out
.fname
.s
);
936 write_time
= finfo
.all_info
.out
.write_time
;
937 write_time
+= i
*1000000;
938 write_time
/= 1000000;
939 write_time
*= 1000000;
942 sinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
943 sinfo
.basic_info
.in
.file
.handle
= h1
;
944 sinfo
.basic_info
.in
.write_time
= write_time
;
945 sinfo
.basic_info
.in
.attrib
= stinfo
.all_info
.out
.attrib
;
946 status
= smb2_setinfo_file(tree
, &sinfo
);
947 CHECK_STATUS(status
, NT_STATUS_OK
);
949 stream_size
= i
*8192;
952 sinfo
.end_of_file_info
.level
=
953 RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
954 sinfo
.end_of_file_info
.in
.file
.handle
= h1
;
955 sinfo
.end_of_file_info
.in
.size
= stream_size
;
956 status
= smb2_setinfo_file(tree
, &sinfo
);
957 CHECK_STATUS(status
, NT_STATUS_OK
);
959 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
960 stinfo
.generic
.in
.file
.handle
= h1
;
961 status
= smb2_getinfo_file(tree
, mem_ctx
, &stinfo
);
962 CHECK_STATUS(status
, NT_STATUS_OK
);
963 if (!torture_setting_bool(tctx
, "samba3", false)) {
964 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
966 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
967 finfo
.all_info
.out
.attrib
);
969 CHECK_VALUE(stinfo
.all_info
.out
.size
,
971 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
972 finfo
.all_info
.out
.delete_pending
);
973 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
974 finfo
.all_info
.out
.directory
);
975 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
976 finfo
.all_info
.out
.ea_size
);
978 io
.smb2
.in
.fname
= fname
;
979 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
980 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
981 CHECK_STATUS(status
, NT_STATUS_OK
);
982 ret
&= check_stream_list(tree
, tctx
, fname
, 4, four
,
983 io
.smb2
.out
.file
.handle
);
985 smb2_util_close(tree
, h1
);
989 torture_comment(tctx
, "(%s): testing stream renames\n", __location__
);
990 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
991 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
|
992 SEC_FILE_WRITE_ATTRIBUTE
|
994 io
.smb2
.in
.fname
= snamer1
;
995 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
996 CHECK_STATUS(status
, NT_STATUS_OK
);
997 h1
= io
.smb2
.out
.file
.handle
;
998 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five1
,
999 io
.smb2
.out
.file
.handle
);
1002 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1003 sinfo
.rename_information
.in
.file
.handle
= h1
;
1004 sinfo
.rename_information
.in
.overwrite
= true;
1005 sinfo
.rename_information
.in
.root_fid
= 0;
1006 sinfo
.rename_information
.in
.new_name
= ":AfterRename:$DATA";
1007 status
= smb2_setinfo_file(tree
, &sinfo
);
1008 CHECK_STATUS(status
, NT_STATUS_OK
);
1010 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five2
,
1011 io
.smb2
.out
.file
.handle
);
1014 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1015 sinfo
.rename_information
.in
.file
.handle
= h1
;
1016 sinfo
.rename_information
.in
.overwrite
= false;
1017 sinfo
.rename_information
.in
.root_fid
= 0;
1018 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1019 status
= smb2_setinfo_file(tree
, &sinfo
);
1020 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
1022 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five2
,
1023 io
.smb2
.out
.file
.handle
);
1026 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1027 sinfo
.rename_information
.in
.file
.handle
= h1
;
1028 sinfo
.rename_information
.in
.overwrite
= true;
1029 sinfo
.rename_information
.in
.root_fid
= 0;
1030 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1031 status
= smb2_setinfo_file(tree
, &sinfo
);
1032 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1034 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five2
,
1035 io
.smb2
.out
.file
.handle
);
1037 /* TODO: we need to test more rename combinations */
1040 smb2_util_close(tree
, h1
);
1041 status
= smb2_util_unlink(tree
, fname
);
1042 smb2_deltree(tree
, DNAME
);
1043 talloc_free(mem_ctx
);
1051 static bool test_stream_names2(struct torture_context
*tctx
,
1052 struct smb2_tree
*tree
)
1054 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1057 const char *fname
= DNAME
"\\stream_names2.txt";
1059 struct smb2_handle h
, h1
;
1062 smb2_util_unlink(tree
, fname
);
1063 smb2_deltree(tree
, DNAME
);
1065 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1066 CHECK_STATUS(status
, NT_STATUS_OK
);
1068 torture_comment(tctx
, "(%s) testing stream names\n", __location__
);
1069 ZERO_STRUCT(io
.smb2
);
1070 io
.smb2
.in
.create_flags
= 0;
1071 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1072 io
.smb2
.in
.create_options
= 0;
1073 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1074 io
.smb2
.in
.share_access
= 0;
1075 io
.smb2
.in
.alloc_size
= 0;
1076 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1077 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1078 io
.smb2
.in
.security_flags
= 0;
1079 io
.smb2
.in
.fname
= fname
;
1080 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1081 CHECK_STATUS(status
, NT_STATUS_OK
);
1082 h1
= io
.smb2
.out
.file
.handle
;
1084 for (i
=0x01; i
< 0x7F; i
++) {
1085 char *path
= talloc_asprintf(mem_ctx
, "%s:Stream%c0x%02X:$DATA",
1093 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1096 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1101 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1102 io
.smb2
.in
.fname
= path
;
1103 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1104 if (!NT_STATUS_EQUAL(status
, expected
)) {
1105 torture_comment(tctx
,
1106 "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1107 __location__
, fname
, isprint(i
)?(char)i
:' ', i
,
1108 isprint(i
)?"":" (not printable)",
1109 nt_errstr(expected
));
1111 CHECK_STATUS(status
, expected
);
1117 smb2_util_close(tree
, h1
);
1118 status
= smb2_util_unlink(tree
, fname
);
1119 smb2_deltree(tree
, DNAME
);
1120 talloc_free(mem_ctx
);
1125 #define CHECK_CALL_HANDLE(call, rightstatus) do { \
1126 check_handle = true; \
1127 call_name = #call; \
1128 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1129 sfinfo.generic.in.file.handle = h1; \
1130 status = smb2_setinfo_file(tree, &sfinfo); \
1131 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1132 torture_result(tctx, TORTURE_FAIL, \
1133 "(%s) %s - %s (should be %s)\n", \
1134 __location__, #call, \
1135 nt_errstr(status), nt_errstr(rightstatus)); \
1138 finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
1139 finfo1.generic.in.file.handle = h1; \
1140 status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
1141 if (!NT_STATUS_IS_OK(status2)) { \
1142 torture_result(tctx, TORTURE_FAIL, \
1143 "(%s) %s pathinfo - %s\n", \
1144 __location__, #call, nt_errstr(status)); \
1151 static bool test_stream_rename(struct torture_context
*tctx
,
1152 struct smb2_tree
*tree
)
1154 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1155 NTSTATUS status
, status2
;
1157 const char *fname
= DNAME
"\\stream_rename.txt";
1158 const char *sname1
, *sname2
;
1159 union smb_fileinfo finfo1
;
1160 union smb_setfileinfo sfinfo
;
1162 struct smb2_handle h
, h1
;
1164 const char *call_name
;
1166 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
1167 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
1170 smb2_util_unlink(tree
, fname
);
1171 smb2_deltree(tree
, DNAME
);
1173 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1174 CHECK_STATUS(status
, NT_STATUS_OK
);
1176 torture_comment(tctx
, "(%s) testing stream renames\n", __location__
);
1177 ZERO_STRUCT(io
.smb2
);
1178 io
.smb2
.in
.create_flags
= 0;
1179 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
|
1180 SEC_FILE_WRITE_ATTRIBUTE
|
1181 SEC_RIGHTS_FILE_ALL
;
1182 io
.smb2
.in
.create_options
= 0;
1183 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1184 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1185 NTCREATEX_SHARE_ACCESS_WRITE
|
1186 NTCREATEX_SHARE_ACCESS_DELETE
;
1187 io
.smb2
.in
.alloc_size
= 0;
1188 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1189 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1190 io
.smb2
.in
.security_flags
= 0;
1191 io
.smb2
.in
.fname
= sname1
;
1193 /* Create two streams. */
1194 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1195 CHECK_STATUS(status
, NT_STATUS_OK
);
1196 h1
= io
.smb2
.out
.file
.handle
;
1197 smb2_util_close(tree
, h1
);
1199 io
.smb2
.in
.fname
= sname2
;
1200 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1201 CHECK_STATUS(status
, NT_STATUS_OK
);
1202 h1
= io
.smb2
.out
.file
.handle
;
1204 smb2_util_close(tree
, h1
);
1207 * Open the second stream.
1210 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1211 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1212 CHECK_STATUS(status
, NT_STATUS_OK
);
1213 h1
= io
.smb2
.out
.file
.handle
;
1216 * Now rename the second stream onto the first.
1219 ZERO_STRUCT(sfinfo
);
1221 sfinfo
.rename_information
.in
.overwrite
= 1;
1222 sfinfo
.rename_information
.in
.root_fid
= 0;
1223 sfinfo
.rename_information
.in
.new_name
= ":Stream One";
1224 CHECK_CALL_HANDLE(RENAME_INFORMATION
, NT_STATUS_OK
);
1226 smb2_util_close(tree
, h1
);
1227 status
= smb2_util_unlink(tree
, fname
);
1228 smb2_deltree(tree
, DNAME
);
1229 talloc_free(mem_ctx
);
1234 static bool test_stream_rename2(struct torture_context
*tctx
,
1235 struct smb2_tree
*tree
)
1237 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1240 const char *fname1
= DNAME
"\\stream_rename2.txt";
1241 const char *fname2
= DNAME
"\\stream2_rename2.txt";
1242 const char *stream_name1
= ":Stream One:$DATA";
1243 const char *stream_name2
= ":Stream Two:$DATA";
1244 const char *stream_name_default
= "::$DATA";
1248 struct smb2_handle h
, h1
;
1249 union smb_setfileinfo sinfo
;
1251 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname1
, "Stream One");
1252 sname2
= talloc_asprintf(mem_ctx
, "%s:%s", fname1
, "Stream Two");
1254 smb2_util_unlink(tree
, fname1
);
1255 smb2_util_unlink(tree
, fname2
);
1256 smb2_deltree(tree
, DNAME
);
1258 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1259 CHECK_STATUS(status
, NT_STATUS_OK
);
1261 ZERO_STRUCT(io
.smb2
);
1262 io
.smb2
.in
.create_flags
= 0;
1263 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1264 SEC_FILE_WRITE_DATA
|
1266 SEC_FILE_APPEND_DATA
|
1267 SEC_STD_READ_CONTROL
;
1268 io
.smb2
.in
.create_options
= 0;
1269 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1270 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1271 NTCREATEX_SHARE_ACCESS_WRITE
|
1272 NTCREATEX_SHARE_ACCESS_DELETE
;
1273 io
.smb2
.in
.alloc_size
= 0;
1274 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1275 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1276 io
.smb2
.in
.security_flags
= 0;
1277 io
.smb2
.in
.fname
= sname1
;
1279 /* Open/create new stream. */
1280 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1281 CHECK_STATUS(status
, NT_STATUS_OK
);
1283 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1286 * Reopen the stream for SMB2 renames.
1288 io
.smb2
.in
.fname
= sname1
;
1289 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1290 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1291 CHECK_STATUS(status
, NT_STATUS_OK
);
1292 h1
= io
.smb2
.out
.file
.handle
;
1295 * Check SMB2 rename of a stream using :<stream>.
1297 torture_comment(tctx
, "(%s) Checking SMB2 rename of a stream using "
1298 ":<stream>\n", __location__
);
1300 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION_SMB2
;
1301 sinfo
.rename_information
.in
.file
.handle
= h1
;
1302 sinfo
.rename_information
.in
.overwrite
= 1;
1303 sinfo
.rename_information
.in
.root_fid
= 0;
1304 sinfo
.rename_information
.in
.new_name
= stream_name1
;
1305 status
= smb2_setinfo_file(tree
, &sinfo
);
1306 CHECK_STATUS(status
, NT_STATUS_OK
);
1309 * Check SMB2 rename of an overwriting stream using :<stream>.
1311 torture_comment(tctx
, "(%s) Checking SMB2 rename of an overwriting "
1312 "stream using :<stream>\n", __location__
);
1314 /* Create second stream. */
1315 io
.smb2
.in
.fname
= sname2
;
1316 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1317 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1318 CHECK_STATUS(status
, NT_STATUS_OK
);
1319 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1321 /* Rename the first stream onto the second. */
1322 sinfo
.rename_information
.in
.file
.handle
= h1
;
1323 sinfo
.rename_information
.in
.new_name
= stream_name2
;
1324 status
= smb2_setinfo_file(tree
, &sinfo
);
1325 CHECK_STATUS(status
, NT_STATUS_OK
);
1327 smb2_util_close(tree
, h1
);
1330 * Reopen the stream with the new name.
1332 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1333 io
.smb2
.in
.fname
= sname2
;
1334 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1335 CHECK_STATUS(status
, NT_STATUS_OK
);
1336 h1
= io
.smb2
.out
.file
.handle
;
1339 * Check SMB2 rename of a stream using <base>:<stream>.
1341 torture_comment(tctx
, "(%s) Checking SMB2 rename of a stream using "
1342 "<base>:<stream>\n", __location__
);
1343 sinfo
.rename_information
.in
.file
.handle
= h1
;
1344 sinfo
.rename_information
.in
.new_name
= sname1
;
1345 status
= smb2_setinfo_file(tree
, &sinfo
);
1346 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
1348 if (!torture_setting_bool(tctx
, "samba4", false)) {
1350 * Check SMB2 rename to the default stream using :<stream>.
1352 torture_comment(tctx
, "(%s) Checking SMB2 rename to default stream "
1353 "using :<stream>\n", __location__
);
1354 sinfo
.rename_information
.in
.file
.handle
= h1
;
1355 sinfo
.rename_information
.in
.new_name
= stream_name_default
;
1356 status
= smb2_setinfo_file(tree
, &sinfo
);
1357 CHECK_STATUS(status
, NT_STATUS_OK
);
1360 smb2_util_close(tree
, h1
);
1363 smb2_util_close(tree
, h1
);
1364 status
= smb2_util_unlink(tree
, fname1
);
1365 status
= smb2_util_unlink(tree
, fname2
);
1366 smb2_deltree(tree
, DNAME
);
1367 talloc_free(mem_ctx
);
1372 static bool create_file_with_stream(struct torture_context
*tctx
,
1373 struct smb2_tree
*tree
,
1374 TALLOC_CTX
*mem_ctx
,
1375 const char *base_fname
,
1382 /* Create a file with a stream */
1383 ZERO_STRUCT(io
.smb2
);
1384 io
.smb2
.in
.create_flags
= 0;
1385 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1386 SEC_FILE_WRITE_DATA
|
1387 SEC_FILE_APPEND_DATA
|
1388 SEC_STD_READ_CONTROL
;
1389 io
.smb2
.in
.create_options
= 0;
1390 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1391 io
.smb2
.in
.share_access
= 0;
1392 io
.smb2
.in
.alloc_size
= 0;
1393 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1394 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1395 io
.smb2
.in
.security_flags
= 0;
1396 io
.smb2
.in
.fname
= stream
;
1398 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1399 CHECK_STATUS(status
, NT_STATUS_OK
);
1402 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1407 /* Test how streams interact with create dispositions */
1408 static bool test_stream_create_disposition(struct torture_context
*tctx
,
1409 struct smb2_tree
*tree
)
1411 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1414 const char *fname
= DNAME
"\\stream_create_disp.txt";
1415 const char *stream
= "Stream One:$DATA";
1416 const char *fname_stream
;
1417 const char *default_stream_name
= "::$DATA";
1418 const char *stream_list
[2];
1420 struct smb2_handle h
, h1
;
1422 /* clean slate .. */
1423 smb2_util_unlink(tree
, fname
);
1424 smb2_deltree(tree
, fname
);
1425 smb2_deltree(tree
, DNAME
);
1427 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1428 CHECK_STATUS(status
, NT_STATUS_OK
);
1430 fname_stream
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, stream
);
1432 stream_list
[0] = talloc_asprintf(mem_ctx
, ":%s", stream
);
1433 stream_list
[1] = default_stream_name
;
1435 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1440 /* Open the base file with OPEN */
1441 ZERO_STRUCT(io
.smb2
);
1442 io
.smb2
.in
.create_flags
= 0;
1443 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1444 SEC_FILE_WRITE_DATA
|
1445 SEC_FILE_APPEND_DATA
|
1446 SEC_STD_READ_CONTROL
;
1447 io
.smb2
.in
.create_options
= 0;
1448 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1449 io
.smb2
.in
.share_access
= 0;
1450 io
.smb2
.in
.alloc_size
= 0;
1451 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1452 io
.smb2
.in
.security_flags
= 0;
1453 io
.smb2
.in
.fname
= fname
;
1456 * check create open: sanity check
1458 torture_comment(tctx
, "(%s) Checking create disp: open\n",
1460 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1461 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1462 CHECK_STATUS(status
, NT_STATUS_OK
);
1463 if (!check_stream_list(tree
, tctx
, fname
, 2, stream_list
,
1464 io
.smb2
.out
.file
.handle
)) {
1467 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1470 * check create overwrite
1472 torture_comment(tctx
, "(%s) Checking create disp: overwrite\n",
1474 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE
;
1475 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1476 CHECK_STATUS(status
, NT_STATUS_OK
);
1477 if (!check_stream_list(tree
, tctx
, fname
, 1, &default_stream_name
,
1478 io
.smb2
.out
.file
.handle
)) {
1481 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1484 * check create overwrite_if
1486 torture_comment(tctx
, "(%s) Checking create disp: overwrite_if\n",
1488 smb2_util_unlink(tree
, fname
);
1489 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
, fname_stream
))
1492 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1493 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1494 CHECK_STATUS(status
, NT_STATUS_OK
);
1495 if (!check_stream_list(tree
, tctx
, fname
, 1, &default_stream_name
,
1496 io
.smb2
.out
.file
.handle
)) {
1499 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1502 * check create supersede
1504 torture_comment(tctx
, "(%s) Checking create disp: supersede\n",
1506 smb2_util_unlink(tree
, fname
);
1507 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1512 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_SUPERSEDE
;
1513 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1514 CHECK_STATUS(status
, NT_STATUS_OK
);
1515 if (!check_stream_list(tree
, tctx
, fname
, 1, &default_stream_name
,
1516 io
.smb2
.out
.file
.handle
)) {
1519 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1522 * check create overwrite_if on a stream.
1524 torture_comment(tctx
, "(%s) Checking create disp: overwrite_if on "
1525 "stream\n", __location__
);
1526 smb2_util_unlink(tree
, fname
);
1527 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1532 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1533 io
.smb2
.in
.fname
= fname_stream
;
1534 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1535 CHECK_STATUS(status
, NT_STATUS_OK
);
1536 if (!check_stream_list(tree
, tctx
, fname
, 2, stream_list
,
1537 io
.smb2
.out
.file
.handle
)) {
1540 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1542 smb2_util_close(tree
, h1
);
1543 smb2_util_unlink(tree
, fname
);
1544 smb2_deltree(tree
, DNAME
);
1545 talloc_free(mem_ctx
);
1550 static bool open_stream(struct smb2_tree
*tree
,
1551 struct torture_context
*mem_ctx
,
1553 struct smb2_handle
*h_out
)
1558 ZERO_STRUCT(io
.smb2
);
1559 io
.smb2
.in
.create_flags
= 0;
1560 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1561 SEC_FILE_WRITE_DATA
|
1562 SEC_FILE_APPEND_DATA
|
1563 SEC_STD_READ_CONTROL
|
1564 SEC_FILE_WRITE_ATTRIBUTE
;
1565 io
.smb2
.in
.create_options
= 0;
1566 io
.smb2
.in
.file_attributes
= 0;
1567 io
.smb2
.in
.share_access
= 0;
1568 io
.smb2
.in
.alloc_size
= 0;
1569 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1570 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1571 io
.smb2
.in
.security_flags
= 0;
1572 io
.smb2
.in
.fname
= fname
;
1574 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1575 if (!NT_STATUS_IS_OK(status
)) {
1578 *h_out
= io
.smb2
.out
.file
.handle
;
1583 /* Test the effect of setting attributes on a stream. */
1584 static bool test_stream_attributes(struct torture_context
*tctx
,
1585 struct smb2_tree
*tree
)
1587 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1591 const char *fname
= DNAME
"\\stream_attr.txt";
1592 const char *stream
= "Stream One:$DATA";
1593 const char *fname_stream
;
1594 struct smb2_handle h
, h1
;
1595 union smb_fileinfo finfo
;
1596 union smb_setfileinfo sfinfo
;
1597 time_t basetime
= (time(NULL
) - 86400) & ~1;
1599 torture_comment(tctx
, "(%s) testing attribute setting on stream\n",
1602 /* clean slate .. */
1603 smb2_util_unlink(tree
, fname
);
1604 smb2_deltree(tree
, fname
);
1605 smb2_deltree(tree
, DNAME
);
1607 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1608 CHECK_STATUS(status
, NT_STATUS_OK
);
1610 fname_stream
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, stream
);
1612 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1613 ret
= create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1619 ZERO_STRUCT(io
.smb2
);
1620 io
.smb2
.in
.fname
= fname
;
1621 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1622 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1623 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1624 NTCREATEX_SHARE_ACCESS_WRITE
|
1625 NTCREATEX_SHARE_ACCESS_DELETE
;
1626 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1627 CHECK_STATUS(status
, NT_STATUS_OK
);
1630 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
1631 finfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
1632 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
1633 CHECK_STATUS(status
, NT_STATUS_OK
);
1635 if (finfo
.basic_info
.out
.attrib
!= FILE_ATTRIBUTE_ARCHIVE
) {
1636 torture_comment(tctx
, "(%s) Incorrect attrib %x - should be "
1637 "%x\n", __location__
,
1638 (unsigned int)finfo
.basic_info
.out
.attrib
,
1639 (unsigned int)FILE_ATTRIBUTE_ARCHIVE
);
1644 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1645 /* Now open the stream name. */
1647 if (!open_stream(tree
, tctx
, fname_stream
, &h1
)) {
1651 /* Change the time on the stream. */
1652 ZERO_STRUCT(sfinfo
);
1653 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, basetime
);
1654 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1655 sfinfo
.generic
.in
.file
.handle
= h1
;
1656 status
= smb2_setinfo_file(tree
, &sfinfo
);
1657 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1658 torture_comment(tctx
, "(%s) %s - %s (should be %s)\n",
1659 __location__
, "SETATTR",
1660 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1665 smb2_util_close(tree
, h1
);
1667 ZERO_STRUCT(io
.smb2
);
1668 io
.smb2
.in
.fname
= fname
;
1669 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1670 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1671 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1672 CHECK_STATUS(status
, NT_STATUS_OK
);
1673 h1
= io
.smb2
.out
.file
.handle
;
1676 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
1677 finfo
.generic
.in
.file
.handle
= h1
;
1678 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
1679 if (!NT_STATUS_IS_OK(status
)) {
1680 torture_comment(tctx
, "(%s) %s pathinfo - %s\n",
1681 __location__
, "SETATTRE", nt_errstr(status
));
1686 if (nt_time_to_unix(finfo
.basic_info
.out
.write_time
) != basetime
) {
1687 torture_comment(tctx
, "(%s) time incorrect.\n", __location__
);
1691 smb2_util_close(tree
, h1
);
1693 if (!open_stream(tree
, tctx
, fname_stream
, &h1
)) {
1697 /* Changing attributes on stream */
1698 ZERO_STRUCT(sfinfo
);
1699 sfinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_READONLY
;
1701 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1702 sfinfo
.generic
.in
.file
.handle
= h1
;
1703 status
= smb2_setinfo_file(tree
, &sfinfo
);
1704 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1705 torture_comment(tctx
, "(%s) %s - %s (should be %s)\n",
1706 __location__
, "SETATTR",
1707 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1712 smb2_util_close(tree
, h1
);
1714 ZERO_STRUCT(io
.smb2
);
1715 io
.smb2
.in
.fname
= fname
;
1716 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1717 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
;
1718 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1719 CHECK_STATUS(status
, NT_STATUS_OK
);
1720 h1
= io
.smb2
.out
.file
.handle
;
1723 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
1724 finfo
.generic
.in
.file
.handle
= h1
;
1725 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
1726 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
1729 smb2_util_close(tree
, h1
);
1730 smb2_util_unlink(tree
, fname
);
1731 smb2_deltree(tree
, DNAME
);
1732 talloc_free(mem_ctx
);
1739 basic testing of streams calls SMB2
1741 struct torture_suite
*torture_smb2_streams_init(void)
1743 struct torture_suite
*suite
=
1744 torture_suite_create(talloc_autofree_context(), "streams");
1746 torture_suite_add_1smb2_test(suite
, "dir", test_stream_dir
);
1747 torture_suite_add_1smb2_test(suite
, "io", test_stream_io
);
1748 torture_suite_add_1smb2_test(suite
, "sharemodes", test_stream_sharemodes
);
1749 torture_suite_add_1smb2_test(suite
, "names", test_stream_names
);
1750 torture_suite_add_1smb2_test(suite
, "names2", test_stream_names2
);
1751 torture_suite_add_1smb2_test(suite
, "rename", test_stream_rename
);
1752 torture_suite_add_1smb2_test(suite
, "rename2", test_stream_rename2
);
1753 torture_suite_add_1smb2_test(suite
, "create-disposition", test_stream_create_disposition
);
1754 torture_suite_add_1smb2_test(suite
, "attributes", test_stream_attributes
);
1755 torture_suite_add_1smb2_test(suite
, "delete", test_stream_delete
);
1757 suite
->description
= talloc_strdup(suite
, "SMB2-STREAM tests");