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_comment(tctx,"(%s) Incorrect value %s='%s' - " \
77 __location__, #v, (v)?(v):"NULL", \
78 (correct)?(correct):"NULL"); \
83 static int qsort_string(char * const *s1
, char * const *s2
)
85 return strcmp(*s1
, *s2
);
88 static int qsort_stream(const struct stream_struct
* s1
, const struct stream_struct
*s2
)
90 return strcmp(s1
->stream_name
.s
, s2
->stream_name
.s
);
93 static bool check_stream(struct smb2_tree
*tree
,
100 struct smb2_handle handle
;
101 struct smb2_create create
;
104 const char *full_name
;
106 full_name
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, sname
);
109 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
110 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
111 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
112 create
.in
.fname
= full_name
;
114 status
= smb2_create(tree
, mem_ctx
, &create
);
115 if (!NT_STATUS_IS_OK(status
)) {
119 torture_comment(mem_ctx
, "Unable to open stream %s\n",
125 handle
= create
.out
.file
.handle
;
132 r
.in
.file
.handle
= handle
;
133 r
.in
.length
= strlen(value
)+11;
136 status
= smb2_read(tree
, tree
, &r
);
138 if (!NT_STATUS_IS_OK(status
)) {
139 torture_comment(mem_ctx
, "(%s) Failed to read %lu bytes from "
140 "stream '%s'\n", location
, (long)strlen(value
), full_name
);
144 if (memcmp(r
.out
.data
.data
, value
, strlen(value
)) != 0) {
145 torture_comment(mem_ctx
, "(%s) Bad data in stream\n", location
);
149 smb2_util_close(tree
, handle
);
153 static bool check_stream_list(struct smb2_tree
*tree
,
154 struct torture_context
*tctx
,
158 struct smb2_handle h
)
160 union smb_fileinfo finfo
;
163 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
165 struct stream_struct
*stream_sort
;
168 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFORMATION
;
169 finfo
.generic
.in
.file
.handle
= h
;
171 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
172 if (!NT_STATUS_IS_OK(status
)) {
173 torture_comment(tctx
, "(%s) smb_raw_pathinfo failed: %s\n",
174 __location__
, nt_errstr(status
));
178 if (finfo
.stream_info
.out
.num_streams
!= num_exp
) {
179 torture_comment(tctx
, "(%s) expected %d streams, got %d\n",
180 __location__
, num_exp
, finfo
.stream_info
.out
.num_streams
);
189 exp_sort
= talloc_memdup(tmp_ctx
, exp
, num_exp
* sizeof(*exp
));
191 if (exp_sort
== NULL
) {
195 TYPESAFE_QSORT(exp_sort
, num_exp
, qsort_string
);
197 stream_sort
= talloc_memdup(tmp_ctx
, finfo
.stream_info
.out
.streams
,
198 finfo
.stream_info
.out
.num_streams
*
199 sizeof(*stream_sort
));
201 if (stream_sort
== NULL
) {
205 TYPESAFE_QSORT(stream_sort
, finfo
.stream_info
.out
.num_streams
, qsort_stream
);
207 for (i
=0; i
<num_exp
; i
++) {
208 if (strcmp(exp_sort
[i
], stream_sort
[i
].stream_name
.s
) != 0) {
209 torture_comment(tctx
,
210 "(%s) expected stream name %s, got %s\n",
211 __location__
, exp_sort
[i
],
212 stream_sort
[i
].stream_name
.s
);
219 talloc_free(tmp_ctx
);
224 static bool test_stream_dir(struct torture_context
*tctx
,
225 struct smb2_tree
*tree
)
227 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
230 const char *fname
= DNAME
"\\stream.txt";
233 const char *basedir_data
;
234 struct smb2_handle h
;
236 smb2_util_unlink(tree
, fname
);
237 smb2_deltree(tree
, DNAME
);
239 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
240 CHECK_STATUS(status
, NT_STATUS_OK
);
242 basedir_data
= talloc_asprintf(mem_ctx
, "%s::$DATA", DNAME
);
243 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
244 torture_comment(tctx
, "%s\n", sname1
);
246 torture_comment(tctx
, "(%s) opening non-existant directory stream\n",
248 ZERO_STRUCT(io
.smb2
);
249 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
250 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
251 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
252 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
253 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
254 io
.smb2
.in
.share_access
= 0;
255 io
.smb2
.in
.alloc_size
= 0;
256 io
.smb2
.in
.security_flags
= 0;
257 io
.smb2
.in
.fname
= sname1
;
258 io
.smb2
.in
.create_flags
= 0;
259 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
260 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
262 torture_comment(tctx
, "(%s) opening basedir stream\n", __location__
);
263 ZERO_STRUCT(io
.smb2
);
264 io
.smb2
.in
.create_flags
= 0;
265 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
266 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
267 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
268 io
.smb2
.in
.share_access
= 0;
269 io
.smb2
.in
.alloc_size
= 0;
270 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
271 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
272 io
.smb2
.in
.security_flags
= 0;
273 io
.smb2
.in
.fname
= basedir_data
;
274 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
275 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
277 torture_comment(tctx
, "(%s) opening basedir ::$DATA stream\n",
279 ZERO_STRUCT(io
.smb2
);
280 io
.smb2
.in
.create_flags
= 0x10;
281 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
282 io
.smb2
.in
.create_options
= 0;
283 io
.smb2
.in
.file_attributes
= 0;
284 io
.smb2
.in
.share_access
= 0;
285 io
.smb2
.in
.alloc_size
= 0;
286 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
287 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
288 io
.smb2
.in
.security_flags
= 0;
289 io
.smb2
.in
.fname
= basedir_data
;
290 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
291 CHECK_STATUS(status
, NT_STATUS_FILE_IS_A_DIRECTORY
);
293 torture_comment(tctx
, "(%s) list the streams on the basedir\n",
295 ret
&= check_stream_list(tree
, mem_ctx
, DNAME
, 0, NULL
, h
);
297 smb2_util_unlink(tree
, fname
);
298 smb2_deltree(tree
, DNAME
);
299 talloc_free(mem_ctx
);
304 static bool test_stream_io(struct torture_context
*tctx
,
305 struct smb2_tree
*tree
)
307 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
310 const char *fname
= DNAME
"\\stream.txt";
311 const char *sname1
, *sname2
;
313 struct smb2_handle h
, h2
;
315 const char *one
[] = { "::$DATA" };
316 const char *two
[] = { "::$DATA", ":Second Stream:$DATA" };
317 const char *three
[] = { "::$DATA", ":Stream One:$DATA",
318 ":Second Stream:$DATA" };
320 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
321 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
324 smb2_util_unlink(tree
, fname
);
325 smb2_deltree(tree
, DNAME
);
327 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
328 CHECK_STATUS(status
, NT_STATUS_OK
);
330 torture_comment(tctx
, "(%s) creating a stream on a non-existant file\n",
333 ZERO_STRUCT(io
.smb2
);
334 io
.smb2
.in
.create_flags
= 0;
335 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
336 io
.smb2
.in
.create_options
= 0;
337 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
338 io
.smb2
.in
.share_access
= 0;
339 io
.smb2
.in
.alloc_size
= 0;
340 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
341 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
342 io
.smb2
.in
.security_flags
= 0;
343 io
.smb2
.in
.fname
= sname1
;
344 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
345 CHECK_STATUS(status
, NT_STATUS_OK
);
346 h2
= io
.smb2
.out
.file
.handle
;
348 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
351 torture_comment(tctx
, "(%s) check that open of base file is allowed\n", __location__
);
352 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
353 io
.smb2
.in
.fname
= fname
;
354 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
355 CHECK_STATUS(status
, NT_STATUS_OK
);
356 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
358 torture_comment(tctx
, "(%s) writing to stream\n", __location__
);
359 status
= smb2_util_write(tree
, h2
, "test data", 0, 9);
360 CHECK_STATUS(status
, NT_STATUS_OK
);
362 smb2_util_close(tree
, h2
);
364 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
365 "Stream One", "test data");
367 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
368 io
.smb2
.in
.fname
= sname1
;
369 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
370 CHECK_STATUS(status
, NT_STATUS_OK
);
371 h2
= io
.smb2
.out
.file
.handle
;
373 torture_comment(tctx
, "(%s) modifying stream\n", __location__
);
374 status
= smb2_util_write(tree
, h2
, "MORE DATA ", 5, 10);
375 CHECK_STATUS(status
, NT_STATUS_OK
);
377 smb2_util_close(tree
, h2
);
379 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
380 "Stream One:$FOO", NULL
);
382 torture_comment(tctx
, "(%s) creating a stream2 on a existing file\n",
384 io
.smb2
.in
.fname
= sname2
;
385 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
386 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
387 CHECK_STATUS(status
, NT_STATUS_OK
);
388 h2
= io
.smb2
.out
.file
.handle
;
390 torture_comment(tctx
, "(%s) modifying stream\n", __location__
);
391 status
= smb2_util_write(tree
, h2
, "SECOND STREAM", 0, 13);
392 CHECK_STATUS(status
, NT_STATUS_OK
);
393 smb2_util_close(tree
, h2
);
395 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
396 "Stream One", "test MORE DATA ");
398 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
399 "Stream One:$DATA", "test MORE DATA ");
401 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
402 "Stream One:", NULL
);
404 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
405 "Second Stream", "SECOND STREAM");
407 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
408 "SECOND STREAM:$DATA", "SECOND STREAM");
409 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
410 "Second Stream:$DATA", "SECOND STREAM");
412 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
413 "Second Stream:", NULL
);
415 ret
&= check_stream(tree
, __location__
, mem_ctx
, fname
,
416 "Second Stream:$FOO", NULL
);
418 io
.smb2
.in
.fname
= sname2
;
419 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
420 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
421 CHECK_STATUS(status
, NT_STATUS_OK
);
422 h2
= io
.smb2
.out
.file
.handle
;
423 check_stream_list(tree
, tctx
, fname
, 3, three
, h2
);
425 smb2_util_close(tree
, h2
);
427 torture_comment(tctx
, "(%s) deleting stream\n", __location__
);
428 status
= smb2_util_unlink(tree
, sname1
);
429 CHECK_STATUS(status
, NT_STATUS_OK
);
431 io
.smb2
.in
.fname
= sname2
;
432 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
433 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
434 CHECK_STATUS(status
, NT_STATUS_OK
);
435 h2
= io
.smb2
.out
.file
.handle
;
436 check_stream_list(tree
, tctx
, fname
, 2, two
, h2
);
437 smb2_util_close(tree
, h2
);
439 torture_comment(tctx
, "(%s) delete a stream via delete-on-close\n",
441 io
.smb2
.in
.fname
= sname2
;
442 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
443 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
444 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
445 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
447 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
448 CHECK_STATUS(status
, NT_STATUS_OK
);
449 h2
= io
.smb2
.out
.file
.handle
;
451 smb2_util_close(tree
, h2
);
452 status
= smb2_util_unlink(tree
, sname2
);
453 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
455 io
.smb2
.in
.fname
= fname
;
456 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
457 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
458 h2
= io
.smb2
.out
.file
.handle
;
459 check_stream_list(tree
,tctx
, fname
, 1, one
, h2
);
460 smb2_util_close(tree
, h2
);
462 if (!torture_setting_bool(tctx
, "samba4", false)) {
463 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
464 io
.smb2
.in
.fname
= sname1
;
465 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
466 CHECK_STATUS(status
, NT_STATUS_OK
);
467 smb2_util_close(tree
, io
.ntcreatex
.out
.file
.handle
);
468 io
.smb2
.in
.fname
= sname2
;
469 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
470 CHECK_STATUS(status
, NT_STATUS_OK
);
471 smb2_util_close(tree
, io
.ntcreatex
.out
.file
.handle
);
472 torture_comment(tctx
, "(%s) deleting file\n", __location__
);
473 status
= smb2_util_unlink(tree
, fname
);
474 CHECK_STATUS(status
, NT_STATUS_OK
);
479 smb2_util_close(tree
, h2
);
480 smb2_deltree(tree
, DNAME
);
481 talloc_free(mem_ctx
);
487 test stream sharemodes
489 static bool test_stream_sharemodes(struct torture_context
*tctx
,
490 struct smb2_tree
*tree
)
492 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
495 const char *fname
= DNAME
"\\stream_share.txt";
496 const char *sname1
, *sname2
;
498 struct smb2_handle h
, h1
, h2
;
500 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
501 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
504 smb2_util_unlink(tree
, fname
);
505 smb2_deltree(tree
, DNAME
);
507 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
508 CHECK_STATUS(status
, NT_STATUS_OK
);
510 torture_comment(tctx
, "(%s) Testing stream share mode conflicts\n",
512 ZERO_STRUCT(io
.smb2
);
513 io
.generic
.level
= RAW_OPEN_SMB2
;
514 io
.smb2
.in
.create_flags
= 0;
515 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
516 io
.smb2
.in
.create_options
= 0;
517 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
518 io
.smb2
.in
.share_access
= 0;
519 io
.smb2
.in
.alloc_size
= 0;
520 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
521 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
522 io
.smb2
.in
.security_flags
= 0;
523 io
.smb2
.in
.fname
= sname1
;
525 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
526 CHECK_STATUS(status
, NT_STATUS_OK
);
527 h1
= io
.smb2
.out
.file
.handle
;
530 * A different stream does not give a sharing violation
533 io
.smb2
.in
.fname
= sname2
;
534 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
535 CHECK_STATUS(status
, NT_STATUS_OK
);
536 h2
= io
.smb2
.out
.file
.handle
;
539 * ... whereas the same stream does with unchanged access/share_access
543 io
.smb2
.in
.fname
= sname1
;
544 io
.smb2
.in
.create_disposition
= 0;
545 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
546 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
548 io
.smb2
.in
.fname
= sname2
;
549 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
550 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
553 smb2_util_close(tree
, h1
);
554 smb2_util_close(tree
, h2
);
555 status
= smb2_util_unlink(tree
, fname
);
556 smb2_deltree(tree
, DNAME
);
557 talloc_free(mem_ctx
);
563 * Test FILE_SHARE_DELETE on streams
565 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
566 * with SEC_STD_DELETE.
568 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
569 * be opened with SEC_STD_DELETE.
571 * A stream held open with FILE_SHARE_DELETE allows the file to be
572 * deleted. After the main file is deleted, access to the open file descriptor
573 * still works, but all name-based access to both the main file as well as the
574 * stream is denied with DELETE pending.
576 * This means, an open of the main file with SEC_STD_DELETE should walk all
577 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
578 * SHARING_VIOLATION, the main open fails.
580 * Closing the main file after delete_on_close has been set does not really
581 * unlink it but leaves the corresponding share mode entry with
582 * delete_on_close being set around until all streams are closed.
584 * Opening a stream must also look at the main file's share mode entry, look
585 * at the delete_on_close bit and potentially return DELETE_PENDING.
588 static bool test_stream_delete(struct torture_context
*tctx
,
589 struct smb2_tree
*tree
)
591 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
594 const char *fname
= DNAME
"\\stream_delete.txt";
597 struct smb2_handle h
, h1
;
600 if (torture_setting_bool(tctx
, "samba4", false)) {
601 torture_comment(tctx
, "Skipping test as samba4 is enabled\n");
605 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
608 smb2_util_unlink(tree
, fname
);
609 smb2_deltree(tree
, fname
);
610 smb2_deltree(tree
, DNAME
);
612 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
613 CHECK_STATUS(status
, NT_STATUS_OK
);
615 torture_comment(tctx
, "(%s) opening non-existant file stream\n",
617 ZERO_STRUCT(io
.smb2
);
618 io
.smb2
.in
.create_flags
= 0;
619 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
620 io
.smb2
.in
.create_options
= 0;
621 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
622 io
.smb2
.in
.share_access
= 0;
623 io
.smb2
.in
.alloc_size
= 0;
624 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
625 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
626 io
.smb2
.in
.security_flags
= 0;
627 io
.smb2
.in
.fname
= sname1
;
629 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
630 CHECK_STATUS(status
, NT_STATUS_OK
);
631 h1
= io
.smb2
.out
.file
.handle
;
633 status
= smb2_util_write(tree
, h1
, "test data", 0, 9);
634 CHECK_STATUS(status
, NT_STATUS_OK
);
637 * One stream opened without FILE_SHARE_DELETE prevents the main file
638 * to be deleted or even opened with DELETE access
641 status
= smb2_util_unlink(tree
, fname
);
642 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
644 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
645 io
.smb2
.in
.fname
= fname
;
646 io
.smb2
.in
.desired_access
= SEC_STD_DELETE
;
647 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
648 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
650 smb2_util_close(tree
, h1
);
653 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
656 io
.smb2
.in
.fname
= sname1
;
657 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
658 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
659 NTCREATEX_SHARE_ACCESS_READ
|
660 NTCREATEX_SHARE_ACCESS_WRITE
;
661 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
662 CHECK_STATUS(status
, NT_STATUS_OK
);
663 h1
= io
.smb2
.out
.file
.handle
;
665 status
= smb2_util_unlink(tree
, fname
);
666 CHECK_STATUS(status
, NT_STATUS_OK
);
669 * file access still works on the stream while the main file is closed
672 r
.in
.file
.handle
= h1
;
676 status
= smb2_read(tree
, tree
, &r
);
677 CHECK_STATUS(status
, NT_STATUS_OK
);
680 * name-based access to both the main file and the stream does not
681 * work anymore but gives DELETE_PENDING
684 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
685 io
.smb2
.in
.fname
= fname
;
686 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
687 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
690 * older S3 doesn't do this
693 io
.smb2
.in
.fname
= sname1
;
694 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
695 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
697 smb2_util_close(tree
, h1
);
700 * After closing the stream the file is really gone.
703 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
704 io
.smb2
.in
.fname
= fname
;
705 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
706 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
709 smb2_util_close(tree
, h1
);
710 smb2_util_unlink(tree
, fname
);
711 smb2_deltree(tree
, DNAME
);
712 talloc_free(mem_ctx
);
720 static bool test_stream_names(struct torture_context
*tctx
,
721 struct smb2_tree
*tree
)
723 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
726 union smb_fileinfo finfo
;
727 union smb_fileinfo stinfo
;
728 union smb_setfileinfo sinfo
;
729 const char *fname
= DNAME
"\\stream_names.txt";
730 const char *sname1
, *sname1b
, *sname1c
, *sname1d
;
731 const char *sname2
, *snamew
, *snamew2
;
732 const char *snamer1
, *snamer2
;
734 struct smb2_handle h
, h1
, h2
, h3
;
736 const char *four
[4] = {
738 ":\x05Stream\n One:$DATA",
739 ":MStream Two:$DATA",
742 const char *five1
[5] = {
744 ":\x05Stream\n One:$DATA",
745 ":BeforeRename:$DATA",
746 ":MStream Two:$DATA",
749 const char *five2
[5] = {
751 ":\x05Stream\n One:$DATA",
752 ":AfterRename:$DATA",
753 ":MStream Two:$DATA",
757 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "\x05Stream\n One");
758 sname1b
= talloc_asprintf(mem_ctx
, "%s:", sname1
);
759 sname1c
= talloc_asprintf(mem_ctx
, "%s:$FOO", sname1
);
760 sname1d
= talloc_asprintf(mem_ctx
, "%s:?D*a", sname1
);
761 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
, "MStream Two");
762 snamew
= talloc_asprintf(mem_ctx
, "%s:%s:$DATA", fname
, "?Stream*");
763 snamew2
= talloc_asprintf(mem_ctx
, "%s\\stream*:%s:$DATA", DNAME
,
765 snamer1
= talloc_asprintf(mem_ctx
, "%s:%s:$DATA", fname
,
767 snamer2
= talloc_asprintf(mem_ctx
, "%s:%s:$DATA", fname
, "AfterRename");
770 smb2_util_unlink(tree
, fname
);
771 smb2_deltree(tree
, fname
);
772 smb2_deltree(tree
, DNAME
);
774 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
775 CHECK_STATUS(status
, NT_STATUS_OK
);
777 torture_comment(tctx
, "(%s) testing stream names\n", __location__
);
778 ZERO_STRUCT(io
.smb2
);
779 io
.smb2
.in
.create_flags
= 0;
780 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
781 io
.smb2
.in
.create_options
= 0;
782 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
783 io
.smb2
.in
.share_access
= 0;
784 io
.smb2
.in
.alloc_size
= 0;
785 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
786 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
787 io
.smb2
.in
.security_flags
= 0;
788 io
.smb2
.in
.fname
= sname1
;
790 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
791 CHECK_STATUS(status
, NT_STATUS_OK
);
792 h1
= io
.smb2
.out
.file
.handle
;
795 * A different stream does not give a sharing violation
798 io
.smb2
.in
.fname
= sname2
;
799 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
800 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
801 CHECK_STATUS(status
, NT_STATUS_OK
);
802 h2
= io
.smb2
.out
.file
.handle
;
805 * ... whereas the same stream does with unchanged access/share_access
809 io
.smb2
.in
.fname
= sname1
;
810 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_SUPERSEDE
;
811 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
812 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
814 io
.smb2
.in
.fname
= sname1b
;
815 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
816 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
818 io
.smb2
.in
.fname
= sname1c
;
819 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
820 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
821 /* w2k returns INVALID_PARAMETER */
822 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
824 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
827 io
.smb2
.in
.fname
= sname1d
;
828 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
829 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
830 /* w2k returns INVALID_PARAMETER */
831 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
833 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
836 io
.smb2
.in
.fname
= sname2
;
837 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
838 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
840 io
.smb2
.in
.fname
= snamew
;
841 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
842 CHECK_STATUS(status
, NT_STATUS_OK
);
843 h3
= io
.smb2
.out
.file
.handle
;
845 io
.smb2
.in
.fname
= snamew2
;
846 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
847 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
849 io
.smb2
.in
.fname
= fname
;
850 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
851 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
852 CHECK_STATUS(status
, NT_STATUS_OK
);
853 ret
&= check_stream_list(tree
, tctx
, fname
, 4, four
,
854 io
.smb2
.out
.file
.handle
);
856 smb2_util_close(tree
, h1
);
857 smb2_util_close(tree
, h2
);
858 smb2_util_close(tree
, h3
);
860 if (torture_setting_bool(tctx
, "samba4", true)) {
864 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
865 finfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
866 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
867 CHECK_STATUS(status
, NT_STATUS_OK
);
868 ret
&= check_stream_list(tree
, tctx
, fname
, 4, four
,
869 io
.smb2
.out
.file
.handle
);
871 for (i
=0; i
< 4; i
++) {
873 uint64_t stream_size
;
874 char *path
= talloc_asprintf(tctx
, "%s%s",
877 char *rpath
= talloc_strdup(path
, path
);
878 char *p
= strrchr(rpath
, ':');
886 torture_comment(tctx
, "(%s): i[%u][%s]\n",
887 __location__
, i
,path
);
888 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
889 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
|
890 SEC_FILE_WRITE_ATTRIBUTE
|
892 io
.smb2
.in
.fname
= path
;
893 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
894 CHECK_STATUS(status
, NT_STATUS_OK
);
895 h1
= io
.smb2
.out
.file
.handle
;
897 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
898 finfo
.generic
.in
.file
.path
= fname
;
899 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
900 CHECK_STATUS(status
, NT_STATUS_OK
);
902 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
903 stinfo
.generic
.in
.file
.handle
= h1
;
904 status
= smb2_getinfo_file(tree
, mem_ctx
, &stinfo
);
905 CHECK_STATUS(status
, NT_STATUS_OK
);
906 if (!torture_setting_bool(tctx
, "samba3", false)) {
907 CHECK_NTTIME(stinfo
.all_info
.out
.create_time
,
908 finfo
.all_info
.out
.create_time
);
909 CHECK_NTTIME(stinfo
.all_info
.out
.access_time
,
910 finfo
.all_info
.out
.access_time
);
911 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
912 finfo
.all_info
.out
.write_time
);
913 CHECK_NTTIME(stinfo
.all_info
.out
.change_time
,
914 finfo
.all_info
.out
.change_time
);
916 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
917 finfo
.all_info
.out
.attrib
);
918 CHECK_VALUE(stinfo
.all_info
.out
.size
,
919 finfo
.all_info
.out
.size
);
920 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
921 finfo
.all_info
.out
.delete_pending
);
922 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
923 finfo
.all_info
.out
.directory
);
924 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
925 finfo
.all_info
.out
.ea_size
);
927 stinfo
.generic
.level
= RAW_FILEINFO_NAME_INFORMATION
;
928 stinfo
.generic
.in
.file
.handle
= h1
;
929 status
= smb2_getinfo_file(tree
, mem_ctx
, &stinfo
);
930 CHECK_STATUS(status
, NT_STATUS_OK
);
931 if (!torture_setting_bool(tctx
, "samba3", false)) {
932 CHECK_STR(rpath
, stinfo
.name_info
.out
.fname
.s
);
935 write_time
= finfo
.all_info
.out
.write_time
;
936 write_time
+= i
*1000000;
937 write_time
/= 1000000;
938 write_time
*= 1000000;
941 sinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
942 sinfo
.basic_info
.in
.file
.handle
= h1
;
943 sinfo
.basic_info
.in
.write_time
= write_time
;
944 sinfo
.basic_info
.in
.attrib
= stinfo
.all_info
.out
.attrib
;
945 status
= smb2_setinfo_file(tree
, &sinfo
);
946 CHECK_STATUS(status
, NT_STATUS_OK
);
948 stream_size
= i
*8192;
951 sinfo
.end_of_file_info
.level
=
952 RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
953 sinfo
.end_of_file_info
.in
.file
.handle
= h1
;
954 sinfo
.end_of_file_info
.in
.size
= stream_size
;
955 status
= smb2_setinfo_file(tree
, &sinfo
);
956 CHECK_STATUS(status
, NT_STATUS_OK
);
958 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFORMATION
;
959 stinfo
.generic
.in
.file
.handle
= h1
;
960 status
= smb2_getinfo_file(tree
, mem_ctx
, &stinfo
);
961 CHECK_STATUS(status
, NT_STATUS_OK
);
962 if (!torture_setting_bool(tctx
, "samba3", false)) {
963 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
965 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
966 finfo
.all_info
.out
.attrib
);
968 CHECK_VALUE(stinfo
.all_info
.out
.size
,
970 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
971 finfo
.all_info
.out
.delete_pending
);
972 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
973 finfo
.all_info
.out
.directory
);
974 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
975 finfo
.all_info
.out
.ea_size
);
977 io
.smb2
.in
.fname
= fname
;
978 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
979 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
980 CHECK_STATUS(status
, NT_STATUS_OK
);
981 ret
&= check_stream_list(tree
, tctx
, fname
, 4, four
,
982 io
.smb2
.out
.file
.handle
);
984 smb2_util_close(tree
, h1
);
988 torture_comment(tctx
, "(%s): testing stream renames\n", __location__
);
989 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
990 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
|
991 SEC_FILE_WRITE_ATTRIBUTE
|
993 io
.smb2
.in
.fname
= snamer1
;
994 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
995 CHECK_STATUS(status
, NT_STATUS_OK
);
996 h1
= io
.smb2
.out
.file
.handle
;
997 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five1
,
998 io
.smb2
.out
.file
.handle
);
1001 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1002 sinfo
.rename_information
.in
.file
.handle
= h1
;
1003 sinfo
.rename_information
.in
.overwrite
= true;
1004 sinfo
.rename_information
.in
.root_fid
= 0;
1005 sinfo
.rename_information
.in
.new_name
= ":AfterRename:$DATA";
1006 status
= smb2_setinfo_file(tree
, &sinfo
);
1007 CHECK_STATUS(status
, NT_STATUS_OK
);
1009 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five2
,
1010 io
.smb2
.out
.file
.handle
);
1013 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1014 sinfo
.rename_information
.in
.file
.handle
= h1
;
1015 sinfo
.rename_information
.in
.overwrite
= false;
1016 sinfo
.rename_information
.in
.root_fid
= 0;
1017 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1018 status
= smb2_setinfo_file(tree
, &sinfo
);
1019 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
1021 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five2
,
1022 io
.smb2
.out
.file
.handle
);
1025 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1026 sinfo
.rename_information
.in
.file
.handle
= h1
;
1027 sinfo
.rename_information
.in
.overwrite
= true;
1028 sinfo
.rename_information
.in
.root_fid
= 0;
1029 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1030 status
= smb2_setinfo_file(tree
, &sinfo
);
1031 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1033 ret
&= check_stream_list(tree
,tctx
, fname
, 5, five2
,
1034 io
.smb2
.out
.file
.handle
);
1036 /* TODO: we need to test more rename combinations */
1039 smb2_util_close(tree
, h1
);
1040 status
= smb2_util_unlink(tree
, fname
);
1041 smb2_deltree(tree
, DNAME
);
1042 talloc_free(mem_ctx
);
1050 static bool test_stream_names2(struct torture_context
*tctx
,
1051 struct smb2_tree
*tree
)
1053 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1056 const char *fname
= DNAME
"\\stream_names2.txt";
1058 struct smb2_handle h
, h1
;
1061 smb2_util_unlink(tree
, fname
);
1062 smb2_deltree(tree
, DNAME
);
1064 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1065 CHECK_STATUS(status
, NT_STATUS_OK
);
1067 torture_comment(tctx
, "(%s) testing stream names\n", __location__
);
1068 ZERO_STRUCT(io
.smb2
);
1069 io
.smb2
.in
.create_flags
= 0;
1070 io
.smb2
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1071 io
.smb2
.in
.create_options
= 0;
1072 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1073 io
.smb2
.in
.share_access
= 0;
1074 io
.smb2
.in
.alloc_size
= 0;
1075 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1076 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1077 io
.smb2
.in
.security_flags
= 0;
1078 io
.smb2
.in
.fname
= fname
;
1079 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1080 CHECK_STATUS(status
, NT_STATUS_OK
);
1081 h1
= io
.smb2
.out
.file
.handle
;
1083 for (i
=0x01; i
< 0x7F; i
++) {
1084 char *path
= talloc_asprintf(mem_ctx
, "%s:Stream%c0x%02X:$DATA",
1092 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1095 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1100 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1101 io
.smb2
.in
.fname
= path
;
1102 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1103 if (!NT_STATUS_EQUAL(status
, expected
)) {
1104 torture_comment(tctx
,
1105 "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1106 __location__
, fname
, isprint(i
)?(char)i
:' ', i
,
1107 isprint(i
)?"":" (not printable)",
1108 nt_errstr(expected
));
1110 CHECK_STATUS(status
, expected
);
1116 smb2_util_close(tree
, h1
);
1117 status
= smb2_util_unlink(tree
, fname
);
1118 smb2_deltree(tree
, DNAME
);
1119 talloc_free(mem_ctx
);
1124 #define CHECK_CALL_HANDLE(call, rightstatus) do { \
1125 check_handle = true; \
1126 call_name = #call; \
1127 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1128 sfinfo.generic.in.file.handle = h1; \
1129 status = smb2_setinfo_file(tree, &sfinfo); \
1130 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1131 torture_comment(tctx,"(%s) %s - %s (should be %s)\n", \
1132 __location__, #call, \
1133 nt_errstr(status), nt_errstr(rightstatus)); \
1136 finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
1137 finfo1.generic.in.file.handle = h1; \
1138 status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
1139 if (!NT_STATUS_IS_OK(status2)) { \
1140 torture_comment(tctx,"(%s) %s pathinfo - %s\n", \
1141 __location__, #call, nt_errstr(status)); \
1148 static bool test_stream_rename(struct torture_context
*tctx
,
1149 struct smb2_tree
*tree
)
1151 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1152 NTSTATUS status
, status2
;
1154 const char *fname
= DNAME
"\\stream_rename.txt";
1155 const char *sname1
, *sname2
;
1156 union smb_fileinfo finfo1
;
1157 union smb_setfileinfo sfinfo
;
1159 struct smb2_handle h
, h1
;
1161 const char *call_name
;
1163 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
1164 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
1167 smb2_util_unlink(tree
, fname
);
1168 smb2_deltree(tree
, DNAME
);
1170 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1171 CHECK_STATUS(status
, NT_STATUS_OK
);
1173 torture_comment(tctx
, "(%s) testing stream renames\n", __location__
);
1174 ZERO_STRUCT(io
.smb2
);
1175 io
.smb2
.in
.create_flags
= 0;
1176 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
|
1177 SEC_FILE_WRITE_ATTRIBUTE
|
1178 SEC_RIGHTS_FILE_ALL
;
1179 io
.smb2
.in
.create_options
= 0;
1180 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1181 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1182 NTCREATEX_SHARE_ACCESS_WRITE
|
1183 NTCREATEX_SHARE_ACCESS_DELETE
;
1184 io
.smb2
.in
.alloc_size
= 0;
1185 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1186 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1187 io
.smb2
.in
.security_flags
= 0;
1188 io
.smb2
.in
.fname
= sname1
;
1190 /* Create two streams. */
1191 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1192 CHECK_STATUS(status
, NT_STATUS_OK
);
1193 h1
= io
.smb2
.out
.file
.handle
;
1194 smb2_util_close(tree
, h1
);
1196 io
.smb2
.in
.fname
= sname2
;
1197 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1198 CHECK_STATUS(status
, NT_STATUS_OK
);
1199 h1
= io
.smb2
.out
.file
.handle
;
1201 smb2_util_close(tree
, h1
);
1204 * Open the second stream.
1207 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1208 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1209 CHECK_STATUS(status
, NT_STATUS_OK
);
1210 h1
= io
.smb2
.out
.file
.handle
;
1213 * Now rename the second stream onto the first.
1216 ZERO_STRUCT(sfinfo
);
1218 sfinfo
.rename_information
.in
.overwrite
= 1;
1219 sfinfo
.rename_information
.in
.root_fid
= 0;
1220 sfinfo
.rename_information
.in
.new_name
= ":Stream One";
1221 CHECK_CALL_HANDLE(RENAME_INFORMATION
, NT_STATUS_OK
);
1223 smb2_util_close(tree
, h1
);
1224 status
= smb2_util_unlink(tree
, fname
);
1225 smb2_deltree(tree
, DNAME
);
1226 talloc_free(mem_ctx
);
1231 static bool test_stream_rename2(struct torture_context
*tctx
,
1232 struct smb2_tree
*tree
)
1234 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1237 const char *fname1
= DNAME
"\\stream_rename2.txt";
1238 const char *fname2
= DNAME
"\\stream2_rename2.txt";
1239 const char *stream_name1
= ":Stream One:$DATA";
1240 const char *stream_name2
= ":Stream Two:$DATA";
1241 const char *stream_name_default
= "::$DATA";
1245 struct smb2_handle h
, h1
;
1246 union smb_setfileinfo sinfo
;
1248 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname1
, "Stream One");
1249 sname2
= talloc_asprintf(mem_ctx
, "%s:%s", fname1
, "Stream Two");
1251 smb2_util_unlink(tree
, fname1
);
1252 smb2_util_unlink(tree
, fname2
);
1253 smb2_deltree(tree
, DNAME
);
1255 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1256 CHECK_STATUS(status
, NT_STATUS_OK
);
1258 ZERO_STRUCT(io
.smb2
);
1259 io
.smb2
.in
.create_flags
= 0;
1260 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1261 SEC_FILE_WRITE_DATA
|
1263 SEC_FILE_APPEND_DATA
|
1264 SEC_STD_READ_CONTROL
;
1265 io
.smb2
.in
.create_options
= 0;
1266 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1267 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1268 NTCREATEX_SHARE_ACCESS_WRITE
|
1269 NTCREATEX_SHARE_ACCESS_DELETE
;
1270 io
.smb2
.in
.alloc_size
= 0;
1271 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1272 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1273 io
.smb2
.in
.security_flags
= 0;
1274 io
.smb2
.in
.fname
= sname1
;
1276 /* Open/create new stream. */
1277 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1278 CHECK_STATUS(status
, NT_STATUS_OK
);
1280 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1283 * Reopen the stream for SMB2 renames.
1285 io
.smb2
.in
.fname
= sname1
;
1286 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1287 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1288 CHECK_STATUS(status
, NT_STATUS_OK
);
1289 h1
= io
.smb2
.out
.file
.handle
;
1292 * Check SMB2 rename of a stream using :<stream>.
1294 torture_comment(tctx
, "(%s) Checking SMB2 rename of a stream using "
1295 ":<stream>\n", __location__
);
1297 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION_SMB2
;
1298 sinfo
.rename_information
.in
.file
.handle
= h1
;
1299 sinfo
.rename_information
.in
.overwrite
= 1;
1300 sinfo
.rename_information
.in
.root_fid
= 0;
1301 sinfo
.rename_information
.in
.new_name
= stream_name1
;
1302 status
= smb2_setinfo_file(tree
, &sinfo
);
1303 CHECK_STATUS(status
, NT_STATUS_OK
);
1306 * Check SMB2 rename of an overwriting stream using :<stream>.
1308 torture_comment(tctx
, "(%s) Checking SMB2 rename of an overwriting "
1309 "stream using :<stream>\n", __location__
);
1311 /* Create second stream. */
1312 io
.smb2
.in
.fname
= sname2
;
1313 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1314 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1315 CHECK_STATUS(status
, NT_STATUS_OK
);
1316 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1318 /* Rename the first stream onto the second. */
1319 sinfo
.rename_information
.in
.file
.handle
= h1
;
1320 sinfo
.rename_information
.in
.new_name
= stream_name2
;
1321 status
= smb2_setinfo_file(tree
, &sinfo
);
1322 CHECK_STATUS(status
, NT_STATUS_OK
);
1324 smb2_util_close(tree
, h1
);
1327 * Reopen the stream with the new name.
1329 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1330 io
.smb2
.in
.fname
= sname2
;
1331 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1332 CHECK_STATUS(status
, NT_STATUS_OK
);
1333 h1
= io
.smb2
.out
.file
.handle
;
1336 * Check SMB2 rename of a stream using <base>:<stream>.
1338 torture_comment(tctx
, "(%s) Checking SMB2 rename of a stream using "
1339 "<base>:<stream>\n", __location__
);
1340 sinfo
.rename_information
.in
.file
.handle
= h1
;
1341 sinfo
.rename_information
.in
.new_name
= sname1
;
1342 status
= smb2_setinfo_file(tree
, &sinfo
);
1343 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
1345 if (!torture_setting_bool(tctx
, "samba4", false)) {
1347 * Check SMB2 rename to the default stream using :<stream>.
1349 torture_comment(tctx
, "(%s) Checking SMB2 rename to default stream "
1350 "using :<stream>\n", __location__
);
1351 sinfo
.rename_information
.in
.file
.handle
= h1
;
1352 sinfo
.rename_information
.in
.new_name
= stream_name_default
;
1353 status
= smb2_setinfo_file(tree
, &sinfo
);
1354 CHECK_STATUS(status
, NT_STATUS_OK
);
1357 smb2_util_close(tree
, h1
);
1360 smb2_util_close(tree
, h1
);
1361 status
= smb2_util_unlink(tree
, fname1
);
1362 status
= smb2_util_unlink(tree
, fname2
);
1363 smb2_deltree(tree
, DNAME
);
1364 talloc_free(mem_ctx
);
1369 static bool create_file_with_stream(struct torture_context
*tctx
,
1370 struct smb2_tree
*tree
,
1371 TALLOC_CTX
*mem_ctx
,
1372 const char *base_fname
,
1379 /* Create a file with a stream */
1380 ZERO_STRUCT(io
.smb2
);
1381 io
.smb2
.in
.create_flags
= 0;
1382 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1383 SEC_FILE_WRITE_DATA
|
1384 SEC_FILE_APPEND_DATA
|
1385 SEC_STD_READ_CONTROL
;
1386 io
.smb2
.in
.create_options
= 0;
1387 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1388 io
.smb2
.in
.share_access
= 0;
1389 io
.smb2
.in
.alloc_size
= 0;
1390 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1391 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1392 io
.smb2
.in
.security_flags
= 0;
1393 io
.smb2
.in
.fname
= stream
;
1395 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1396 CHECK_STATUS(status
, NT_STATUS_OK
);
1399 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1404 /* Test how streams interact with create dispositions */
1405 static bool test_stream_create_disposition(struct torture_context
*tctx
,
1406 struct smb2_tree
*tree
)
1408 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1411 const char *fname
= DNAME
"\\stream_create_disp.txt";
1412 const char *stream
= "Stream One:$DATA";
1413 const char *fname_stream
;
1414 const char *default_stream_name
= "::$DATA";
1415 const char *stream_list
[2];
1417 struct smb2_handle h
, h1
;
1419 /* clean slate .. */
1420 smb2_util_unlink(tree
, fname
);
1421 smb2_deltree(tree
, fname
);
1422 smb2_deltree(tree
, DNAME
);
1424 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1425 CHECK_STATUS(status
, NT_STATUS_OK
);
1427 fname_stream
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, stream
);
1429 stream_list
[0] = talloc_asprintf(mem_ctx
, ":%s", stream
);
1430 stream_list
[1] = default_stream_name
;
1432 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1437 /* Open the base file with OPEN */
1438 ZERO_STRUCT(io
.smb2
);
1439 io
.smb2
.in
.create_flags
= 0;
1440 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1441 SEC_FILE_WRITE_DATA
|
1442 SEC_FILE_APPEND_DATA
|
1443 SEC_STD_READ_CONTROL
;
1444 io
.smb2
.in
.create_options
= 0;
1445 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1446 io
.smb2
.in
.share_access
= 0;
1447 io
.smb2
.in
.alloc_size
= 0;
1448 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1449 io
.smb2
.in
.security_flags
= 0;
1450 io
.smb2
.in
.fname
= fname
;
1453 * check create open: sanity check
1455 torture_comment(tctx
, "(%s) Checking create disp: open\n",
1457 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1458 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1459 CHECK_STATUS(status
, NT_STATUS_OK
);
1460 if (!check_stream_list(tree
, tctx
, fname
, 2, stream_list
,
1461 io
.smb2
.out
.file
.handle
)) {
1464 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1467 * check create overwrite
1469 torture_comment(tctx
, "(%s) Checking create disp: overwrite\n",
1471 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE
;
1472 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1473 CHECK_STATUS(status
, NT_STATUS_OK
);
1474 if (!check_stream_list(tree
, tctx
, fname
, 1, &default_stream_name
,
1475 io
.smb2
.out
.file
.handle
)) {
1478 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1481 * check create overwrite_if
1483 torture_comment(tctx
, "(%s) Checking create disp: overwrite_if\n",
1485 smb2_util_unlink(tree
, fname
);
1486 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
, fname_stream
))
1489 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1490 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1491 CHECK_STATUS(status
, NT_STATUS_OK
);
1492 if (!check_stream_list(tree
, tctx
, fname
, 1, &default_stream_name
,
1493 io
.smb2
.out
.file
.handle
)) {
1496 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1499 * check create supersede
1501 torture_comment(tctx
, "(%s) Checking create disp: supersede\n",
1503 smb2_util_unlink(tree
, fname
);
1504 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1509 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_SUPERSEDE
;
1510 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1511 CHECK_STATUS(status
, NT_STATUS_OK
);
1512 if (!check_stream_list(tree
, tctx
, fname
, 1, &default_stream_name
,
1513 io
.smb2
.out
.file
.handle
)) {
1516 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1519 * check create overwrite_if on a stream.
1521 torture_comment(tctx
, "(%s) Checking create disp: overwrite_if on "
1522 "stream\n", __location__
);
1523 smb2_util_unlink(tree
, fname
);
1524 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1529 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1530 io
.smb2
.in
.fname
= fname_stream
;
1531 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1532 CHECK_STATUS(status
, NT_STATUS_OK
);
1533 if (!check_stream_list(tree
, tctx
, fname
, 2, stream_list
,
1534 io
.smb2
.out
.file
.handle
)) {
1537 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1539 smb2_util_close(tree
, h1
);
1540 smb2_util_unlink(tree
, fname
);
1541 smb2_deltree(tree
, DNAME
);
1542 talloc_free(mem_ctx
);
1547 static bool open_stream(struct smb2_tree
*tree
,
1548 struct torture_context
*mem_ctx
,
1550 struct smb2_handle
*h_out
)
1555 ZERO_STRUCT(io
.smb2
);
1556 io
.smb2
.in
.create_flags
= 0;
1557 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
|
1558 SEC_FILE_WRITE_DATA
|
1559 SEC_FILE_APPEND_DATA
|
1560 SEC_STD_READ_CONTROL
|
1561 SEC_FILE_WRITE_ATTRIBUTE
;
1562 io
.smb2
.in
.create_options
= 0;
1563 io
.smb2
.in
.file_attributes
= 0;
1564 io
.smb2
.in
.share_access
= 0;
1565 io
.smb2
.in
.alloc_size
= 0;
1566 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1567 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1568 io
.smb2
.in
.security_flags
= 0;
1569 io
.smb2
.in
.fname
= fname
;
1571 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1572 if (!NT_STATUS_IS_OK(status
)) {
1575 *h_out
= io
.smb2
.out
.file
.handle
;
1580 /* Test the effect of setting attributes on a stream. */
1581 static bool test_stream_attributes(struct torture_context
*tctx
,
1582 struct smb2_tree
*tree
)
1584 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1588 const char *fname
= DNAME
"\\stream_attr.txt";
1589 const char *stream
= "Stream One:$DATA";
1590 const char *fname_stream
;
1591 struct smb2_handle h
, h1
;
1592 union smb_fileinfo finfo
;
1593 union smb_setfileinfo sfinfo
;
1594 time_t basetime
= (time(NULL
) - 86400) & ~1;
1596 torture_comment(tctx
, "(%s) testing attribute setting on stream\n",
1599 /* clean slate .. */
1600 smb2_util_unlink(tree
, fname
);
1601 smb2_deltree(tree
, fname
);
1602 smb2_deltree(tree
, DNAME
);
1604 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1605 CHECK_STATUS(status
, NT_STATUS_OK
);
1607 fname_stream
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, stream
);
1609 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1610 ret
= create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
1616 ZERO_STRUCT(io
.smb2
);
1617 io
.smb2
.in
.fname
= fname
;
1618 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1619 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1620 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1621 NTCREATEX_SHARE_ACCESS_WRITE
|
1622 NTCREATEX_SHARE_ACCESS_DELETE
;
1623 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1624 CHECK_STATUS(status
, NT_STATUS_OK
);
1627 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
1628 finfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
1629 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
1630 CHECK_STATUS(status
, NT_STATUS_OK
);
1632 if (finfo
.basic_info
.out
.attrib
!= FILE_ATTRIBUTE_ARCHIVE
) {
1633 torture_comment(tctx
, "(%s) Incorrect attrib %x - should be "
1634 "%x\n", __location__
,
1635 (unsigned int)finfo
.basic_info
.out
.attrib
,
1636 (unsigned int)FILE_ATTRIBUTE_ARCHIVE
);
1641 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1642 /* Now open the stream name. */
1644 if (!open_stream(tree
, tctx
, fname_stream
, &h1
)) {
1648 /* Change the time on the stream. */
1649 ZERO_STRUCT(sfinfo
);
1650 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, basetime
);
1651 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1652 sfinfo
.generic
.in
.file
.handle
= h1
;
1653 status
= smb2_setinfo_file(tree
, &sfinfo
);
1654 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1655 torture_comment(tctx
, "(%s) %s - %s (should be %s)\n",
1656 __location__
, "SETATTR",
1657 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1662 smb2_util_close(tree
, h1
);
1664 ZERO_STRUCT(io
.smb2
);
1665 io
.smb2
.in
.fname
= fname
;
1666 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1667 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1668 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1669 CHECK_STATUS(status
, NT_STATUS_OK
);
1670 h1
= io
.smb2
.out
.file
.handle
;
1673 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
1674 finfo
.generic
.in
.file
.handle
= h1
;
1675 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
1676 if (!NT_STATUS_IS_OK(status
)) {
1677 torture_comment(tctx
, "(%s) %s pathinfo - %s\n",
1678 __location__
, "SETATTRE", nt_errstr(status
));
1683 if (nt_time_to_unix(finfo
.basic_info
.out
.write_time
) != basetime
) {
1684 torture_comment(tctx
, "(%s) time incorrect.\n", __location__
);
1688 smb2_util_close(tree
, h1
);
1690 if (!open_stream(tree
, tctx
, fname_stream
, &h1
)) {
1694 /* Changing attributes on stream */
1695 ZERO_STRUCT(sfinfo
);
1696 sfinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_READONLY
;
1698 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1699 sfinfo
.generic
.in
.file
.handle
= h1
;
1700 status
= smb2_setinfo_file(tree
, &sfinfo
);
1701 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1702 torture_comment(tctx
, "(%s) %s - %s (should be %s)\n",
1703 __location__
, "SETATTR",
1704 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1709 smb2_util_close(tree
, h1
);
1711 ZERO_STRUCT(io
.smb2
);
1712 io
.smb2
.in
.fname
= fname
;
1713 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1714 io
.smb2
.in
.desired_access
= SEC_FILE_READ_DATA
;
1715 status
= smb2_create(tree
, mem_ctx
, &(io
.smb2
));
1716 CHECK_STATUS(status
, NT_STATUS_OK
);
1717 h1
= io
.smb2
.out
.file
.handle
;
1720 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
1721 finfo
.generic
.in
.file
.handle
= h1
;
1722 status
= smb2_getinfo_file(tree
, mem_ctx
, &finfo
);
1723 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
1726 smb2_util_close(tree
, h1
);
1727 smb2_util_unlink(tree
, fname
);
1728 smb2_deltree(tree
, DNAME
);
1729 talloc_free(mem_ctx
);
1736 basic testing of streams calls SMB2
1738 struct torture_suite
*torture_smb2_streams_init(void)
1740 struct torture_suite
*suite
=
1741 torture_suite_create(talloc_autofree_context(), "streams");
1743 torture_suite_add_1smb2_test(suite
, "dir", test_stream_dir
);
1744 torture_suite_add_1smb2_test(suite
, "io", test_stream_io
);
1745 torture_suite_add_1smb2_test(suite
, "sharemodes", test_stream_sharemodes
);
1746 torture_suite_add_1smb2_test(suite
, "names", test_stream_names
);
1747 torture_suite_add_1smb2_test(suite
, "names2", test_stream_names2
);
1748 torture_suite_add_1smb2_test(suite
, "rename", test_stream_rename
);
1749 torture_suite_add_1smb2_test(suite
, "rename2", test_stream_rename2
);
1750 torture_suite_add_1smb2_test(suite
, "create-disposition", test_stream_create_disposition
);
1751 torture_suite_add_1smb2_test(suite
, "attributes", test_stream_attributes
);
1752 torture_suite_add_1smb2_test(suite
, "delete", test_stream_delete
);
1754 suite
->description
= talloc_strdup(suite
, "SMB2-STREAM tests");