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 "system/locale.h"
24 #include "torture/torture.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "system/filesys.h"
27 #include "libcli/libcli.h"
28 #include "torture/util.h"
30 #define BASEDIR "\\teststreams"
32 #define CHECK_STATUS(status, correct) \
33 torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
35 #define CHECK_VALUE(v, correct) \
36 torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
38 #define CHECK_NTTIME(v, correct) \
39 torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
41 #define CHECK_STR(v, correct) do { \
43 if ((v) && !(correct)) { \
45 } else if (!(v) && (correct)) { \
47 } else if (!(v) && !(correct)) { \
49 } else if (strcmp((v), (correct)) == 0) { \
54 torture_assert(tctx,ok,\
55 talloc_asprintf(tctx, "got '%s', expected '%s'",\
56 (v)?(v):"NULL", (correct)?(correct):"NULL")); \
60 check that a stream has the right contents
62 static bool check_stream(struct smbcli_state
*cli
, const char *location
,
64 const char *fname
, const char *sname
,
68 const char *full_name
;
72 full_name
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, sname
);
74 fnum
= smbcli_open(cli
->tree
, full_name
, O_RDONLY
, DENY_NONE
);
78 printf("(%s) should have failed stream open of %s\n",
86 printf("(%s) Failed to open stream '%s' - %s\n",
87 location
, full_name
, smbcli_errstr(cli
->tree
));
91 buf
= talloc_array(mem_ctx
, uint8_t, strlen(value
)+11);
93 ret
= smbcli_read(cli
->tree
, fnum
, buf
, 0, strlen(value
)+11);
94 if (ret
!= strlen(value
)) {
95 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
96 location
, (long)strlen(value
), full_name
, (int)ret
);
100 if (memcmp(buf
, value
, strlen(value
)) != 0) {
101 printf("(%s) Bad data in stream\n", location
);
105 smbcli_close(cli
->tree
, fnum
);
109 static int qsort_string(const void *v1
, const void *v2
)
111 char * const *s1
= (char * const *)v1
;
112 char * const *s2
= (char * const *)v2
;
113 return strcmp(*s1
, *s2
);
116 static int qsort_stream(const void *v1
, const void *v2
)
118 const struct stream_struct
* s1
= (const struct stream_struct
*)v1
;
119 const struct stream_struct
* s2
= (const struct stream_struct
*)v2
;
120 return strcmp(s1
->stream_name
.s
, s2
->stream_name
.s
);
123 static bool check_stream_list(struct torture_context
*tctx
,
124 struct smbcli_state
*cli
, const char *fname
,
125 int num_exp
, const char **exp
)
127 union smb_fileinfo finfo
;
130 TALLOC_CTX
*tmp_ctx
= talloc_new(cli
);
132 struct stream_struct
*stream_sort
;
136 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
137 finfo
.generic
.in
.file
.path
= fname
;
139 status
= smb_raw_pathinfo(cli
->tree
, tmp_ctx
, &finfo
);
140 CHECK_STATUS(status
, NT_STATUS_OK
);
142 CHECK_VALUE(finfo
.stream_info
.out
.num_streams
, num_exp
);
149 exp_sort
= (char **)talloc_memdup(tmp_ctx
, exp
, num_exp
* sizeof(*exp
));
151 if (exp_sort
== NULL
) {
155 qsort(exp_sort
, num_exp
, sizeof(*exp_sort
), qsort_string
);
157 stream_sort
= (struct stream_struct
*)talloc_memdup(tmp_ctx
,
158 finfo
.stream_info
.out
.streams
,
159 finfo
.stream_info
.out
.num_streams
*
160 sizeof(*stream_sort
));
162 if (stream_sort
== NULL
) {
166 qsort(stream_sort
, finfo
.stream_info
.out
.num_streams
,
167 sizeof(*stream_sort
), qsort_stream
);
169 for (i
=0; i
<num_exp
; i
++) {
170 if (strcmp(exp_sort
[i
], stream_sort
[i
].stream_name
.s
) != 0) {
178 talloc_free(tmp_ctx
);
182 for (i
=0; i
<num_exp
; i
++) {
183 torture_comment(tctx
, "stream names '%s' '%s'\n",
184 exp_sort
[i
], stream_sort
[i
].stream_name
.s
);
186 CHECK_STR(stream_sort
[fail
].stream_name
.s
, exp_sort
[fail
]);
187 talloc_free(tmp_ctx
);
192 test bahavior of streams on directories
194 static bool test_stream_dir(struct torture_context
*tctx
,
195 struct smbcli_state
*cli
)
199 const char *fname
= BASEDIR
"\\stream.txt";
202 const char *basedir_data
;
204 if (!torture_setup_dir(cli
, BASEDIR
)) {
208 basedir_data
= talloc_asprintf(tctx
, "%s::$DATA", BASEDIR
);
209 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
211 printf("(%s) opening non-existant directory stream\n", __location__
);
212 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
213 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
214 io
.ntcreatex
.in
.flags
= 0;
215 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
216 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
217 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
218 io
.ntcreatex
.in
.share_access
= 0;
219 io
.ntcreatex
.in
.alloc_size
= 0;
220 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
221 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
222 io
.ntcreatex
.in
.security_flags
= 0;
223 io
.ntcreatex
.in
.fname
= sname1
;
224 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
225 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
227 printf("(%s) opening basedir stream\n", __location__
);
228 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
229 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
230 io
.ntcreatex
.in
.flags
= 0;
231 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
232 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
233 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_DIRECTORY
;
234 io
.ntcreatex
.in
.share_access
= 0;
235 io
.ntcreatex
.in
.alloc_size
= 0;
236 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
237 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
238 io
.ntcreatex
.in
.security_flags
= 0;
239 io
.ntcreatex
.in
.fname
= basedir_data
;
240 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
241 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
243 printf("(%s) opening basedir ::$DATA stream\n", __location__
);
244 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
245 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
246 io
.ntcreatex
.in
.flags
= 0x10;
247 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
248 io
.ntcreatex
.in
.create_options
= 0;
249 io
.ntcreatex
.in
.file_attr
= 0;
250 io
.ntcreatex
.in
.share_access
= 0;
251 io
.ntcreatex
.in
.alloc_size
= 0;
252 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
253 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
254 io
.ntcreatex
.in
.security_flags
= 0;
255 io
.ntcreatex
.in
.fname
= basedir_data
;
256 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
257 CHECK_STATUS(status
, NT_STATUS_FILE_IS_A_DIRECTORY
);
259 printf("(%s) list the streams on the basedir\n", __location__
);
260 ret
&= check_stream_list(tctx
, cli
, BASEDIR
, 0, NULL
);
262 smbcli_deltree(cli
->tree
, BASEDIR
);
267 test basic behavior of streams on directories
269 static bool test_stream_io(struct torture_context
*tctx
,
270 struct smbcli_state
*cli
)
274 const char *fname
= BASEDIR
"\\stream.txt";
275 const char *sname1
, *sname2
;
280 const char *one
[] = { "::$DATA" };
281 const char *two
[] = { "::$DATA", ":Second Stream:$DATA" };
282 const char *three
[] = { "::$DATA", ":Stream One:$DATA",
283 ":Second Stream:$DATA" };
285 if (!torture_setup_dir(cli
, BASEDIR
)) {
289 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
290 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
292 printf("(%s) creating a stream on a non-existant file\n", __location__
);
293 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
294 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
295 io
.ntcreatex
.in
.flags
= 0;
296 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
297 io
.ntcreatex
.in
.create_options
= 0;
298 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
299 io
.ntcreatex
.in
.share_access
= 0;
300 io
.ntcreatex
.in
.alloc_size
= 0;
301 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
302 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
303 io
.ntcreatex
.in
.security_flags
= 0;
304 io
.ntcreatex
.in
.fname
= sname1
;
305 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
306 CHECK_STATUS(status
, NT_STATUS_OK
);
307 fnum
= io
.ntcreatex
.out
.file
.fnum
;
309 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", NULL
);
311 printf("(%s) check that open of base file is allowed\n", __location__
);
312 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
313 io
.ntcreatex
.in
.fname
= fname
;
314 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
315 CHECK_STATUS(status
, NT_STATUS_OK
);
316 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
318 printf("(%s) writing to stream\n", __location__
);
319 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
320 CHECK_VALUE(retsize
, 9);
322 smbcli_close(cli
->tree
, fnum
);
324 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test data");
326 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
327 io
.ntcreatex
.in
.fname
= sname1
;
328 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
329 CHECK_STATUS(status
, NT_STATUS_OK
);
330 fnum
= io
.ntcreatex
.out
.file
.fnum
;
332 printf("(%s) modifying stream\n", __location__
);
333 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "MORE DATA ", 5, 10);
334 CHECK_VALUE(retsize
, 10);
336 smbcli_close(cli
->tree
, fnum
);
338 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$FOO", NULL
);
340 printf("(%s) creating a stream2 on a existing file\n", __location__
);
341 io
.ntcreatex
.in
.fname
= sname2
;
342 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
343 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
344 CHECK_STATUS(status
, NT_STATUS_OK
);
345 fnum
= io
.ntcreatex
.out
.file
.fnum
;
347 printf("(%s) modifying stream\n", __location__
);
348 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "SECOND STREAM", 0, 13);
349 CHECK_VALUE(retsize
, 13);
351 smbcli_close(cli
->tree
, fnum
);
353 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test MORE DATA ");
354 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$DATA", "test MORE DATA ");
355 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:", NULL
);
356 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream", "SECOND STREAM");
357 ret
&= check_stream(cli
, __location__
, tctx
, fname
,
358 "SECOND STREAM:$DATA", "SECOND STREAM");
359 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$DATA", "SECOND STREAM");
360 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:", NULL
);
361 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$FOO", NULL
);
363 check_stream_list(tctx
, cli
, fname
, 3, three
);
365 printf("(%s) deleting stream\n", __location__
);
366 status
= smbcli_unlink(cli
->tree
, sname1
);
367 CHECK_STATUS(status
, NT_STATUS_OK
);
369 check_stream_list(tctx
, cli
, fname
, 2, two
);
371 printf("(%s) delete a stream via delete-on-close\n", __location__
);
372 io
.ntcreatex
.in
.fname
= sname2
;
373 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
374 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
375 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
376 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
378 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
379 CHECK_STATUS(status
, NT_STATUS_OK
);
380 fnum
= io
.ntcreatex
.out
.file
.fnum
;
382 smbcli_close(cli
->tree
, fnum
);
383 status
= smbcli_unlink(cli
->tree
, sname2
);
384 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
386 check_stream_list(tctx
, cli
, fname
, 1, one
);
388 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
389 io
.ntcreatex
.in
.fname
= sname1
;
390 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
391 CHECK_STATUS(status
, NT_STATUS_OK
);
392 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
393 io
.ntcreatex
.in
.fname
= sname2
;
394 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
395 CHECK_STATUS(status
, NT_STATUS_OK
);
396 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
398 printf("(%s) deleting file\n", __location__
);
399 status
= smbcli_unlink(cli
->tree
, fname
);
400 CHECK_STATUS(status
, NT_STATUS_OK
);
403 smbcli_close(cli
->tree
, fnum
);
404 smbcli_deltree(cli
->tree
, BASEDIR
);
409 test stream sharemodes
411 static bool test_stream_sharemodes(struct torture_context
*tctx
,
412 struct smbcli_state
*cli
)
416 const char *fname
= BASEDIR
"\\stream.txt";
417 const char *sname1
, *sname2
;
422 if (!torture_setup_dir(cli
, BASEDIR
)) {
426 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
427 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
429 printf("(%s) testing stream share mode conflicts\n", __location__
);
430 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
431 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
432 io
.ntcreatex
.in
.flags
= 0;
433 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
434 io
.ntcreatex
.in
.create_options
= 0;
435 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
436 io
.ntcreatex
.in
.share_access
= 0;
437 io
.ntcreatex
.in
.alloc_size
= 0;
438 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
439 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
440 io
.ntcreatex
.in
.security_flags
= 0;
441 io
.ntcreatex
.in
.fname
= sname1
;
443 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
444 CHECK_STATUS(status
, NT_STATUS_OK
);
445 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
448 * A different stream does not give a sharing violation
451 io
.ntcreatex
.in
.fname
= sname2
;
452 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
453 CHECK_STATUS(status
, NT_STATUS_OK
);
454 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
457 * ... whereas the same stream does with unchanged access/share_access
461 io
.ntcreatex
.in
.fname
= sname1
;
462 io
.ntcreatex
.in
.open_disposition
= 0;
463 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
464 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
466 io
.ntcreatex
.in
.fname
= sname2
;
467 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
468 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
471 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
472 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
473 status
= smbcli_unlink(cli
->tree
, fname
);
474 smbcli_deltree(cli
->tree
, BASEDIR
);
479 * Test FILE_SHARE_DELETE on streams
481 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
482 * with SEC_STD_DELETE.
484 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
485 * be opened with SEC_STD_DELETE.
487 * A stream held open with FILE_SHARE_DELETE allows the file to be
488 * deleted. After the main file is deleted, access to the open file descriptor
489 * still works, but all name-based access to both the main file as well as the
490 * stream is denied with DELETE ending.
492 * This means, an open of the main file with SEC_STD_DELETE should walk all
493 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
494 * SHARING_VIOLATION, the main open fails.
496 * Closing the main file after delete_on_close has been set does not really
497 * unlink it but leaves the corresponding share mode entry with
498 * delete_on_close being set around until all streams are closed.
500 * Opening a stream must also look at the main file's share mode entry, look
501 * at the delete_on_close bit and potentially return DELETE_PENDING.
504 static bool test_stream_delete(struct torture_context
*tctx
,
505 struct smbcli_state
*cli
)
509 const char *fname
= BASEDIR
"\\stream.txt";
515 union smb_fileinfo finfo
;
517 if (!torture_setup_dir(cli
, BASEDIR
)) {
521 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
523 printf("(%s) opening non-existant file stream\n", __location__
);
524 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
525 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
526 io
.ntcreatex
.in
.flags
= 0;
527 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
528 io
.ntcreatex
.in
.create_options
= 0;
529 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
530 io
.ntcreatex
.in
.share_access
= 0;
531 io
.ntcreatex
.in
.alloc_size
= 0;
532 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
533 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
534 io
.ntcreatex
.in
.security_flags
= 0;
535 io
.ntcreatex
.in
.fname
= sname1
;
537 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
538 CHECK_STATUS(status
, NT_STATUS_OK
);
539 fnum
= io
.ntcreatex
.out
.file
.fnum
;
541 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
542 CHECK_VALUE(retsize
, 9);
545 * One stream opened without FILE_SHARE_DELETE prevents the main file
546 * to be deleted or even opened with DELETE access
549 status
= smbcli_unlink(cli
->tree
, fname
);
550 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
552 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
553 io
.ntcreatex
.in
.fname
= fname
;
554 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
555 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
556 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
558 smbcli_close(cli
->tree
, fnum
);
561 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
564 io
.ntcreatex
.in
.fname
= sname1
;
565 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
566 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
567 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
568 CHECK_STATUS(status
, NT_STATUS_OK
);
569 fnum
= io
.ntcreatex
.out
.file
.fnum
;
571 status
= smbcli_unlink(cli
->tree
, fname
);
572 CHECK_STATUS(status
, NT_STATUS_OK
);
575 * file access still works on the stream while the main file is closed
578 retsize
= smbcli_read(cli
->tree
, fnum
, buf
, 0, 9);
579 CHECK_VALUE(retsize
, 9);
581 finfo
.generic
.level
= RAW_FILEINFO_STANDARD
;
582 finfo
.generic
.in
.file
.path
= fname
;
585 * name-based access to both the main file and the stream does not
586 * work anymore but gives DELETE_PENDING
589 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
590 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
593 * older S3 doesn't do this
595 finfo
.generic
.in
.file
.path
= sname1
;
596 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
597 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
600 * fd-based qfileinfo on the stream still works, the stream does not
601 * have the delete-on-close bit set. This could mean that open on the
602 * stream first opens the main file
605 finfo
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
606 finfo
.all_info
.in
.file
.fnum
= fnum
;
608 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo
);
609 CHECK_STATUS(status
, NT_STATUS_OK
);
611 /* w2k and w2k3 return 0 and w2k8 returns 1 */
612 if (TARGET_IS_WINXP(tctx
) || TARGET_IS_W2K3(tctx
) ||
613 TARGET_IS_SAMBA3(tctx
)) {
614 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 0);
616 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 1);
619 smbcli_close(cli
->tree
, fnum
);
622 * After closing the stream the file is really gone.
625 finfo
.generic
.in
.file
.path
= fname
;
626 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
627 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
629 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
631 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
632 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
633 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
634 CHECK_STATUS(status
, NT_STATUS_OK
);
635 fnum
= io
.ntcreatex
.out
.file
.fnum
;
637 finfo
.generic
.in
.file
.path
= fname
;
638 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
639 CHECK_STATUS(status
, NT_STATUS_OK
);
641 smbcli_close(cli
->tree
, fnum
);
643 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
644 CHECK_STATUS(status
, NT_STATUS_OK
);
646 smbcli_close(cli
->tree
, fnum
);
647 smbcli_unlink(cli
->tree
, fname
);
648 smbcli_deltree(cli
->tree
, BASEDIR
);
655 static bool test_stream_names(struct torture_context
*tctx
,
656 struct smbcli_state
*cli
)
660 union smb_fileinfo finfo
;
661 union smb_fileinfo stinfo
;
662 union smb_setfileinfo sinfo
;
663 const char *fname
= BASEDIR
"\\stream_names.txt";
664 const char *sname1
, *sname1b
, *sname1c
, *sname1d
;
665 const char *sname2
, *snamew
, *snamew2
;
666 const char *snamer1
, *snamer2
;
672 const char *four
[4] = {
674 ":\x05Stream\n One:$DATA",
675 ":MStream Two:$DATA",
678 const char *five1
[5] = {
680 ":\x05Stream\n One:$DATA",
681 ":BeforeRename:$DATA",
682 ":MStream Two:$DATA",
685 const char *five2
[5] = {
687 ":\x05Stream\n One:$DATA",
688 ":AfterRename:$DATA",
689 ":MStream Two:$DATA",
693 if (!torture_setup_dir(cli
, BASEDIR
)) {
697 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "\x05Stream\n One");
698 sname1b
= talloc_asprintf(tctx
, "%s:", sname1
);
699 sname1c
= talloc_asprintf(tctx
, "%s:$FOO", sname1
);
700 sname1d
= talloc_asprintf(tctx
, "%s:?D*a", sname1
);
701 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "MStream Two");
702 snamew
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "?Stream*");
703 snamew2
= talloc_asprintf(tctx
, "%s\\stream*:%s:$DATA", BASEDIR
, "?Stream*");
704 snamer1
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "BeforeRename");
705 snamer2
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "AfterRename");
707 printf("(%s) testing stream names\n", __location__
);
708 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
709 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
710 io
.ntcreatex
.in
.flags
= 0;
711 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
712 io
.ntcreatex
.in
.create_options
= 0;
713 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
714 io
.ntcreatex
.in
.share_access
= 0;
715 io
.ntcreatex
.in
.alloc_size
= 0;
716 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
717 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
718 io
.ntcreatex
.in
.security_flags
= 0;
719 io
.ntcreatex
.in
.fname
= fname
;
721 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
722 CHECK_STATUS(status
, NT_STATUS_OK
);
723 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
726 * Make sure the create time of the streams are different from the
730 smbcli_close(cli
->tree
, fnum1
);
732 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
733 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
734 io
.ntcreatex
.in
.flags
= 0;
735 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
736 io
.ntcreatex
.in
.create_options
= 0;
737 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
738 io
.ntcreatex
.in
.share_access
= 0;
739 io
.ntcreatex
.in
.alloc_size
= 0;
740 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
741 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
742 io
.ntcreatex
.in
.security_flags
= 0;
743 io
.ntcreatex
.in
.fname
= sname1
;
745 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
746 CHECK_STATUS(status
, NT_STATUS_OK
);
747 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
750 * A different stream does not give a sharing violation
753 io
.ntcreatex
.in
.fname
= sname2
;
754 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
755 CHECK_STATUS(status
, NT_STATUS_OK
);
756 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
759 * ... whereas the same stream does with unchanged access/share_access
763 io
.ntcreatex
.in
.fname
= sname1
;
764 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
765 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
766 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
768 io
.ntcreatex
.in
.fname
= sname1b
;
769 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
770 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
772 io
.ntcreatex
.in
.fname
= sname1c
;
773 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
774 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
775 /* w2k returns INVALID_PARAMETER */
776 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
778 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
781 io
.ntcreatex
.in
.fname
= sname1d
;
782 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
783 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
784 /* w2k returns INVALID_PARAMETER */
785 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
787 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
790 io
.ntcreatex
.in
.fname
= sname2
;
791 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
792 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
794 io
.ntcreatex
.in
.fname
= snamew
;
795 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
796 CHECK_STATUS(status
, NT_STATUS_OK
);
797 fnum3
= io
.ntcreatex
.out
.file
.fnum
;
799 io
.ntcreatex
.in
.fname
= snamew2
;
800 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
801 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
803 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
805 smbcli_close(cli
->tree
, fnum1
);
806 smbcli_close(cli
->tree
, fnum2
);
807 smbcli_close(cli
->tree
, fnum3
);
809 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
810 finfo
.generic
.in
.file
.path
= fname
;
811 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
812 CHECK_STATUS(status
, NT_STATUS_OK
);
814 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
816 for (i
=0; i
< 4; i
++) {
818 uint64_t stream_size
;
819 char *path
= talloc_asprintf(tctx
, "%s%s",
822 char *rpath
= talloc_strdup(path
, path
);
823 char *p
= strrchr(rpath
, ':');
831 printf("(%s): i[%u][%s]\n", __location__
, i
, path
);
832 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
833 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
834 SEC_FILE_WRITE_ATTRIBUTE
|
836 io
.ntcreatex
.in
.fname
= path
;
837 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
838 CHECK_STATUS(status
, NT_STATUS_OK
);
839 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
841 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
842 finfo
.generic
.in
.file
.path
= fname
;
843 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
844 CHECK_STATUS(status
, NT_STATUS_OK
);
846 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
847 stinfo
.generic
.in
.file
.fnum
= fnum1
;
848 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
849 CHECK_STATUS(status
, NT_STATUS_OK
);
850 if (!torture_setting_bool(tctx
, "samba3", false)) {
851 CHECK_NTTIME(stinfo
.all_info
.out
.create_time
,
852 finfo
.all_info
.out
.create_time
);
853 CHECK_NTTIME(stinfo
.all_info
.out
.access_time
,
854 finfo
.all_info
.out
.access_time
);
855 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
856 finfo
.all_info
.out
.write_time
);
857 CHECK_NTTIME(stinfo
.all_info
.out
.change_time
,
858 finfo
.all_info
.out
.change_time
);
860 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
861 finfo
.all_info
.out
.attrib
);
862 CHECK_VALUE(stinfo
.all_info
.out
.size
,
863 finfo
.all_info
.out
.size
);
864 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
865 finfo
.all_info
.out
.delete_pending
);
866 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
867 finfo
.all_info
.out
.directory
);
868 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
869 finfo
.all_info
.out
.ea_size
);
871 stinfo
.generic
.level
= RAW_FILEINFO_NAME_INFO
;
872 stinfo
.generic
.in
.file
.fnum
= fnum1
;
873 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
874 CHECK_STATUS(status
, NT_STATUS_OK
);
875 if (!torture_setting_bool(tctx
, "samba3", false)) {
876 CHECK_STR(stinfo
.name_info
.out
.fname
.s
, rpath
);
879 write_time
= finfo
.all_info
.out
.write_time
;
880 write_time
+= i
*1000000;
881 write_time
/= 1000000;
882 write_time
*= 1000000;
885 sinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
886 sinfo
.basic_info
.in
.file
.fnum
= fnum1
;
887 sinfo
.basic_info
.in
.write_time
= write_time
;
888 sinfo
.basic_info
.in
.attrib
= stinfo
.all_info
.out
.attrib
;
889 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
890 CHECK_STATUS(status
, NT_STATUS_OK
);
892 stream_size
= i
*8192;
895 sinfo
.end_of_file_info
.level
= RAW_SFILEINFO_END_OF_FILE_INFO
;
896 sinfo
.end_of_file_info
.in
.file
.fnum
= fnum1
;
897 sinfo
.end_of_file_info
.in
.size
= stream_size
;
898 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
899 CHECK_STATUS(status
, NT_STATUS_OK
);
901 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
902 stinfo
.generic
.in
.file
.fnum
= fnum1
;
903 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
904 CHECK_STATUS(status
, NT_STATUS_OK
);
905 if (!torture_setting_bool(tctx
, "samba3", false)) {
906 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
908 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
909 finfo
.all_info
.out
.attrib
);
911 CHECK_VALUE(stinfo
.all_info
.out
.size
,
913 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
914 finfo
.all_info
.out
.delete_pending
);
915 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
916 finfo
.all_info
.out
.directory
);
917 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
918 finfo
.all_info
.out
.ea_size
);
920 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
922 smbcli_close(cli
->tree
, fnum1
);
926 printf("(%s): testing stream renames\n", __location__
);
927 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
928 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
929 SEC_FILE_WRITE_ATTRIBUTE
|
931 io
.ntcreatex
.in
.fname
= snamer1
;
932 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
933 CHECK_STATUS(status
, NT_STATUS_OK
);
934 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
936 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five1
);
939 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
940 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
941 sinfo
.rename_information
.in
.overwrite
= true;
942 sinfo
.rename_information
.in
.root_fid
= 0;
943 sinfo
.rename_information
.in
.new_name
= ":AfterRename:$DATA";
944 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
945 CHECK_STATUS(status
, NT_STATUS_OK
);
947 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
950 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
951 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
952 sinfo
.rename_information
.in
.overwrite
= false;
953 sinfo
.rename_information
.in
.root_fid
= 0;
954 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
955 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
956 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
958 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
961 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
962 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
963 sinfo
.rename_information
.in
.overwrite
= true;
964 sinfo
.rename_information
.in
.root_fid
= 0;
965 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
966 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
967 if (torture_setting_bool(tctx
, "samba4", false) ||
968 torture_setting_bool(tctx
, "samba3", false)) {
969 /* why should this rename be considered invalid?? */
970 CHECK_STATUS(status
, NT_STATUS_OK
);
971 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
973 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
974 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
978 /* TODO: we need to test more rename combinations */
981 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
982 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
983 if (fnum3
!= -1) smbcli_close(cli
->tree
, fnum3
);
984 status
= smbcli_unlink(cli
->tree
, fname
);
985 smbcli_deltree(cli
->tree
, BASEDIR
);
992 static bool test_stream_names2(struct torture_context
*tctx
,
993 struct smbcli_state
*cli
)
997 const char *fname
= BASEDIR
"\\stream_names2.txt";
1002 if (!torture_setup_dir(cli
, BASEDIR
)) {
1006 printf("(%s) testing stream names\n", __location__
);
1007 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1008 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1009 io
.ntcreatex
.in
.flags
= 0;
1010 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
1011 io
.ntcreatex
.in
.create_options
= 0;
1012 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1013 io
.ntcreatex
.in
.share_access
= 0;
1014 io
.ntcreatex
.in
.alloc_size
= 0;
1015 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1016 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1017 io
.ntcreatex
.in
.security_flags
= 0;
1018 io
.ntcreatex
.in
.fname
= fname
;
1019 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1020 CHECK_STATUS(status
, NT_STATUS_OK
);
1021 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
1023 for (i
=0x01; i
< 0x7F; i
++) {
1024 char *path
= talloc_asprintf(tctx
, "%s:Stream%c0x%02X:$DATA",
1032 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1035 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1040 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1041 io
.ntcreatex
.in
.fname
= path
;
1042 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1043 if (!NT_STATUS_EQUAL(status
, expected
)) {
1044 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1045 __location__
, fname
, isprint(i
)?(char)i
:' ', i
,
1046 isprint(i
)?"":" (not printable)",
1047 nt_errstr(expected
));
1049 CHECK_STATUS(status
, expected
);
1055 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
1056 status
= smbcli_unlink(cli
->tree
, fname
);
1057 smbcli_deltree(cli
->tree
, BASEDIR
);
1061 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1062 check_fnum = true; \
1063 call_name = #call; \
1064 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1065 sfinfo.generic.in.file.fnum = fnum; \
1066 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1067 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1068 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1069 nt_errstr(status), nt_errstr(rightstatus)); \
1072 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1073 finfo1.generic.in.file.fnum = fnum; \
1074 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1075 if (!NT_STATUS_IS_OK(status2)) { \
1076 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1083 static bool test_stream_rename(struct torture_context
*tctx
,
1084 struct smbcli_state
*cli
)
1086 NTSTATUS status
, status2
;
1088 const char *fname
= BASEDIR
"\\stream_rename.txt";
1089 const char *sname1
, *sname2
;
1090 union smb_fileinfo finfo1
;
1091 union smb_setfileinfo sfinfo
;
1095 const char *call_name
;
1097 if (!torture_setup_dir(cli
, BASEDIR
)) {
1101 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
1102 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1104 printf("(%s) testing stream renames\n", __location__
);
1105 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1106 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1107 io
.ntcreatex
.in
.flags
= 0;
1108 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1109 SEC_FILE_WRITE_ATTRIBUTE
|
1110 SEC_RIGHTS_FILE_ALL
;
1111 io
.ntcreatex
.in
.create_options
= 0;
1112 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1113 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1114 io
.ntcreatex
.in
.alloc_size
= 0;
1115 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1116 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1117 io
.ntcreatex
.in
.security_flags
= 0;
1118 io
.ntcreatex
.in
.fname
= sname1
;
1120 /* Create two streams. */
1121 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1122 CHECK_STATUS(status
, NT_STATUS_OK
);
1123 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1124 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1126 io
.ntcreatex
.in
.fname
= sname2
;
1127 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1128 CHECK_STATUS(status
, NT_STATUS_OK
);
1129 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1131 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1134 * Open the second stream.
1137 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1138 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1139 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1140 CHECK_STATUS(status
, NT_STATUS_OK
);
1141 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1144 * Now rename the second stream onto the first.
1147 ZERO_STRUCT(sfinfo
);
1149 sfinfo
.rename_information
.in
.overwrite
= 1;
1150 sfinfo
.rename_information
.in
.root_fid
= 0;
1151 sfinfo
.rename_information
.in
.new_name
= ":Stream One";
1152 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1155 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1156 status
= smbcli_unlink(cli
->tree
, fname
);
1157 smbcli_deltree(cli
->tree
, BASEDIR
);
1161 static bool test_stream_rename2(struct torture_context
*tctx
,
1162 struct smbcli_state
*cli
)
1166 const char *fname1
= BASEDIR
"\\stream.txt";
1167 const char *fname2
= BASEDIR
"\\stream2.txt";
1168 const char *stream_name1
= ":Stream One:$DATA";
1169 const char *stream_name2
= ":Stream Two:$DATA";
1170 const char *stream_name_default
= "::$DATA";
1175 union smb_setfileinfo sinfo
;
1176 union smb_rename rio
;
1178 if (!torture_setup_dir(cli
, BASEDIR
)) {
1182 sname1
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream One");
1183 sname2
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream Two");
1185 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1186 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1187 io
.ntcreatex
.in
.flags
= 0;
1188 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1189 SEC_STD_DELETE
|SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1190 io
.ntcreatex
.in
.create_options
= 0;
1191 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1192 io
.ntcreatex
.in
.share_access
= (NTCREATEX_SHARE_ACCESS_READ
|
1193 NTCREATEX_SHARE_ACCESS_WRITE
|
1194 NTCREATEX_SHARE_ACCESS_DELETE
);
1195 io
.ntcreatex
.in
.alloc_size
= 0;
1196 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1197 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1198 io
.ntcreatex
.in
.security_flags
= 0;
1199 io
.ntcreatex
.in
.fname
= sname1
;
1201 /* Open/create new stream. */
1202 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1203 CHECK_STATUS(status
, NT_STATUS_OK
);
1205 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1208 * Check raw rename with <base>:<stream>.
1210 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1212 rio
.generic
.level
= RAW_RENAME_NTRENAME
;
1213 rio
.ntrename
.in
.old_name
= sname1
;
1214 rio
.ntrename
.in
.new_name
= sname2
;
1215 rio
.ntrename
.in
.attrib
= 0;
1216 rio
.ntrename
.in
.cluster_size
= 0;
1217 rio
.ntrename
.in
.flags
= RENAME_FLAG_RENAME
;
1218 status
= smb_raw_rename(cli
->tree
, &rio
);
1219 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1222 * Check raw rename to the default stream using :<stream>.
1224 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1226 rio
.ntrename
.in
.new_name
= stream_name_default
;
1227 status
= smb_raw_rename(cli
->tree
, &rio
);
1228 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
1231 * Check raw rename using :<stream>.
1233 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1235 rio
.ntrename
.in
.new_name
= stream_name2
;
1236 status
= smb_raw_rename(cli
->tree
, &rio
);
1237 CHECK_STATUS(status
, NT_STATUS_OK
);
1240 * Check raw rename of a stream to a file.
1242 printf("(%s) Checking NTRENAME of a stream to a file\n",
1244 rio
.ntrename
.in
.old_name
= sname2
;
1245 rio
.ntrename
.in
.new_name
= fname2
;
1246 status
= smb_raw_rename(cli
->tree
, &rio
);
1247 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1250 * Check raw rename of a file to a stream.
1252 printf("(%s) Checking NTRENAME of a file to a stream\n",
1255 /* Create the file. */
1256 io
.ntcreatex
.in
.fname
= fname2
;
1257 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1258 CHECK_STATUS(status
, NT_STATUS_OK
);
1259 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1261 /* Try the rename. */
1262 rio
.ntrename
.in
.old_name
= fname2
;
1263 rio
.ntrename
.in
.new_name
= sname1
;
1264 status
= smb_raw_rename(cli
->tree
, &rio
);
1265 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
1268 * Reopen the stream for trans2 renames.
1270 io
.ntcreatex
.in
.fname
= sname2
;
1271 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1272 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1273 CHECK_STATUS(status
, NT_STATUS_OK
);
1274 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1277 * Check trans2 rename of a stream using :<stream>.
1279 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1282 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1283 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1284 sinfo
.rename_information
.in
.overwrite
= 1;
1285 sinfo
.rename_information
.in
.root_fid
= 0;
1286 sinfo
.rename_information
.in
.new_name
= stream_name1
;
1287 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1288 CHECK_STATUS(status
, NT_STATUS_OK
);
1291 * Check trans2 rename of an overwriting stream using :<stream>.
1293 printf("(%s) Checking trans2 rename of an overwriting stream using "
1294 ":<stream>\n", __location__
);
1296 /* Create second stream. */
1297 io
.ntcreatex
.in
.fname
= sname2
;
1298 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1299 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1300 CHECK_STATUS(status
, NT_STATUS_OK
);
1301 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1303 /* Rename the first stream onto the second. */
1304 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1305 sinfo
.rename_information
.in
.new_name
= stream_name2
;
1306 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1307 CHECK_STATUS(status
, NT_STATUS_OK
);
1309 smbcli_close(cli
->tree
, fnum
);
1312 * Reopen the stream with the new name.
1314 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1315 io
.ntcreatex
.in
.fname
= sname2
;
1316 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1317 CHECK_STATUS(status
, NT_STATUS_OK
);
1318 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1321 * Check trans2 rename of a stream using <base>:<stream>.
1323 printf("(%s) Checking trans2 rename of a stream using "
1324 "<base>:<stream>\n", __location__
);
1325 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1326 sinfo
.rename_information
.in
.new_name
= sname1
;
1327 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1328 CHECK_STATUS(status
, NT_STATUS_NOT_SUPPORTED
);
1331 * Samba3 doesn't currently support renaming a stream to the default
1332 * stream. This test does pass on windows.
1334 if (torture_setting_bool(tctx
, "samba3", false) ||
1335 torture_setting_bool(tctx
, "samba4", false)) {
1340 * Check trans2 rename to the default stream using :<stream>.
1342 printf("(%s) Checking trans2 rename to defaualt stream using "
1343 ":<stream>\n", __location__
);
1344 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1345 sinfo
.rename_information
.in
.new_name
= stream_name_default
;
1346 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1347 CHECK_STATUS(status
, NT_STATUS_OK
);
1349 smbcli_close(cli
->tree
, fnum
);
1352 smbcli_close(cli
->tree
, fnum
);
1353 status
= smbcli_unlink(cli
->tree
, fname1
);
1354 status
= smbcli_unlink(cli
->tree
, fname2
);
1355 smbcli_deltree(cli
->tree
, BASEDIR
);
1362 static bool test_stream_rename3(struct torture_context
*tctx
,
1363 struct smbcli_state
*cli
)
1365 NTSTATUS status
, status2
;
1367 const char *fname
= BASEDIR
"\\stream_rename.txt";
1368 const char *sname1
, *sname2
;
1369 union smb_fileinfo finfo1
;
1370 union smb_setfileinfo sfinfo
;
1375 const char *call_name
;
1377 if (!torture_setup_dir(cli
, BASEDIR
)) {
1381 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "MStream Two:$DATA");
1382 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1384 printf("(%s) testing stream renames\n", __location__
);
1385 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1386 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1387 io
.ntcreatex
.in
.flags
= 0;
1388 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1389 SEC_FILE_WRITE_ATTRIBUTE
|
1390 SEC_RIGHTS_FILE_ALL
;
1391 io
.ntcreatex
.in
.create_options
= 0;
1392 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1393 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1394 NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1395 io
.ntcreatex
.in
.alloc_size
= 0;
1396 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1397 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1398 io
.ntcreatex
.in
.security_flags
= 0;
1399 io
.ntcreatex
.in
.fname
= sname1
;
1401 /* Create two streams. */
1402 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1403 CHECK_STATUS(status
, NT_STATUS_OK
);
1404 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1405 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1407 io
.ntcreatex
.in
.fname
= sname2
;
1408 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1409 CHECK_STATUS(status
, NT_STATUS_OK
);
1410 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1412 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1414 /* open the second stream. */
1415 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1416 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1417 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1418 CHECK_STATUS(status
, NT_STATUS_OK
);
1419 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1421 /* Keep a handle to the first stream open. */
1422 io
.ntcreatex
.in
.fname
= sname1
;
1423 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1424 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1425 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1426 CHECK_STATUS(status
, NT_STATUS_OK
);
1427 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
1429 ZERO_STRUCT(sfinfo
);
1430 sfinfo
.rename_information
.in
.overwrite
= 1;
1431 sfinfo
.rename_information
.in
.root_fid
= 0;
1432 sfinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1433 if (torture_setting_bool(tctx
, "samba4", false) ||
1434 torture_setting_bool(tctx
, "samba3", false)) {
1435 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1437 CHECK_CALL_FNUM(RENAME_INFORMATION
,
1438 NT_STATUS_INVALID_PARAMETER
);
1443 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1444 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
1445 status
= smbcli_unlink(cli
->tree
, fname
);
1446 smbcli_deltree(cli
->tree
, BASEDIR
);
1450 static bool create_file_with_stream(struct torture_context
*tctx
,
1451 struct smbcli_state
*cli
,
1458 /* Create a file with a stream */
1459 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1460 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1461 io
.ntcreatex
.in
.flags
= 0;
1462 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1463 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1464 io
.ntcreatex
.in
.create_options
= 0;
1465 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1466 io
.ntcreatex
.in
.share_access
= 0;
1467 io
.ntcreatex
.in
.alloc_size
= 0;
1468 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1469 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1470 io
.ntcreatex
.in
.security_flags
= 0;
1471 io
.ntcreatex
.in
.fname
= stream
;
1473 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1474 CHECK_STATUS(status
, NT_STATUS_OK
);
1477 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1481 /* Test how streams interact with create dispositions */
1482 static bool test_stream_create_disposition(struct torture_context
*tctx
,
1483 struct smbcli_state
*cli
)
1487 const char *fname
= BASEDIR
"\\stream.txt";
1488 const char *stream
= "Stream One:$DATA";
1489 const char *fname_stream
;
1490 const char *default_stream_name
= "::$DATA";
1491 const char *stream_list
[2];
1495 if (!torture_setup_dir(cli
, BASEDIR
)) {
1499 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1501 stream_list
[0] = talloc_asprintf(tctx
, ":%s", stream
);
1502 stream_list
[1] = default_stream_name
;
1504 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1508 /* Open the base file with OPEN */
1509 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1510 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1511 io
.ntcreatex
.in
.flags
= 0;
1512 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1513 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1514 io
.ntcreatex
.in
.create_options
= 0;
1515 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1516 io
.ntcreatex
.in
.share_access
= 0;
1517 io
.ntcreatex
.in
.alloc_size
= 0;
1518 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1519 io
.ntcreatex
.in
.security_flags
= 0;
1520 io
.ntcreatex
.in
.fname
= fname
;
1523 * check ntcreatex open: sanity check
1525 printf("(%s) Checking ntcreatex disp: open\n", __location__
);
1526 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1527 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1528 CHECK_STATUS(status
, NT_STATUS_OK
);
1529 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1530 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1535 * check ntcreatex overwrite
1537 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__
);
1538 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
1539 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1540 CHECK_STATUS(status
, NT_STATUS_OK
);
1541 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1542 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1547 * check ntcreatex overwrite_if
1549 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__
);
1550 smbcli_unlink(cli
->tree
, fname
);
1551 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1555 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1556 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1557 CHECK_STATUS(status
, NT_STATUS_OK
);
1558 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1559 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1564 * check ntcreatex supersede
1566 printf("(%s) Checking ntcreatex disp: supersede\n", __location__
);
1567 smbcli_unlink(cli
->tree
, fname
);
1568 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1572 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
1573 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1574 CHECK_STATUS(status
, NT_STATUS_OK
);
1575 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1576 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1581 * check ntcreatex overwrite_if on a stream.
1583 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1585 smbcli_unlink(cli
->tree
, fname
);
1586 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1590 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1591 io
.ntcreatex
.in
.fname
= fname_stream
;
1592 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1593 CHECK_STATUS(status
, NT_STATUS_OK
);
1594 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1595 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1600 * check openx overwrite_if
1602 printf("(%s) Checking openx disp: overwrite_if\n", __location__
);
1603 smbcli_unlink(cli
->tree
, fname
);
1604 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1608 io
.openx
.level
= RAW_OPEN_OPENX
;
1609 io
.openx
.in
.flags
= OPENX_FLAGS_ADDITIONAL_INFO
;
1610 io
.openx
.in
.open_mode
= OPENX_MODE_ACCESS_RDWR
| OPEN_FLAGS_DENY_NONE
;
1611 io
.openx
.in
.search_attrs
= 0;
1612 io
.openx
.in
.file_attrs
= 0;
1613 io
.openx
.in
.write_time
= 0;
1614 io
.openx
.in
.size
= 1024*1024;
1615 io
.openx
.in
.timeout
= 0;
1616 io
.openx
.in
.fname
= fname
;
1618 io
.openx
.in
.open_func
= OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
;
1619 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1620 CHECK_STATUS(status
, NT_STATUS_OK
);
1621 smbcli_close(cli
->tree
, io
.openx
.out
.file
.fnum
);
1622 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1629 smbcli_close(cli
->tree
, fnum
);
1630 smbcli_unlink(cli
->tree
, fname
);
1631 smbcli_deltree(cli
->tree
, BASEDIR
);
1635 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1636 static bool test_stream_large_streaminfo(struct torture_context
*tctx
,
1637 struct smbcli_state
*cli
)
1639 #define LONG_STREAM_SIZE 2
1641 const char *fname
= BASEDIR
"\\stream.txt";
1642 const char *fname_stream
;
1646 union smb_fileinfo finfo
;
1648 if (!torture_setup_dir(cli
, BASEDIR
)) {
1652 lstream_name
= talloc_array(tctx
, char, LONG_STREAM_SIZE
);
1654 for (i
= 0; i
< LONG_STREAM_SIZE
- 1; i
++) {
1655 lstream_name
[i
] = (char)('a' + i
%26);
1657 lstream_name
[LONG_STREAM_SIZE
- 1] = '\0';
1659 torture_comment(tctx
, "(%s) Creating a file with a lot of streams\n", __location__
);
1660 for (i
= 0; i
< 10000; i
++) {
1661 fname_stream
= talloc_asprintf(tctx
, "%s:%s%d", fname
,
1663 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1669 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
1670 finfo
.generic
.in
.file
.path
= fname
;
1672 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1673 CHECK_STATUS(status
, STATUS_BUFFER_OVERFLOW
);
1676 smbcli_unlink(cli
->tree
, fname
);
1677 smbcli_deltree(cli
->tree
, BASEDIR
);
1681 /* Test the effect of setting attributes on a stream. */
1682 static bool test_stream_attributes(struct torture_context
*tctx
,
1683 struct smbcli_state
*cli
)
1688 const char *fname
= BASEDIR
"\\stream_attr.txt";
1689 const char *stream
= "Stream One:$DATA";
1690 const char *fname_stream
;
1692 union smb_fileinfo finfo
;
1693 union smb_setfileinfo sfinfo
;
1694 time_t basetime
= (time(NULL
) - 86400) & ~1;
1696 if (!torture_setup_dir(cli
, BASEDIR
)) {
1700 torture_comment(tctx
, "(%s) testing attribute setting on stream\n", __location__
);
1702 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1704 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1705 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1711 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1712 finfo
.generic
.in
.file
.path
= fname
;
1713 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1714 CHECK_STATUS(status
, NT_STATUS_OK
);
1716 if (finfo
.basic_info
.out
.attrib
!= FILE_ATTRIBUTE_ARCHIVE
) {
1717 printf("(%s) Incorrect attrib %x - should be %x\n", \
1718 __location__
, (unsigned int)finfo
.basic_info
.out
.attrib
,
1719 (unsigned int)FILE_ATTRIBUTE_ARCHIVE
);
1724 /* Now open the stream name. */
1726 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1727 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1728 io
.ntcreatex
.in
.flags
= 0;
1729 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1730 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
|SEC_FILE_WRITE_ATTRIBUTE
);
1731 io
.ntcreatex
.in
.create_options
= 0;
1732 io
.ntcreatex
.in
.file_attr
= 0;
1733 io
.ntcreatex
.in
.share_access
= 0;
1734 io
.ntcreatex
.in
.alloc_size
= 0;
1735 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1736 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1737 io
.ntcreatex
.in
.security_flags
= 0;
1738 io
.ntcreatex
.in
.fname
= fname_stream
;
1740 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1741 CHECK_STATUS(status
, NT_STATUS_OK
);
1743 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1745 /* Change the attributes + time on the stream fnum. */
1746 ZERO_STRUCT(sfinfo
);
1747 sfinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_READONLY
;
1748 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, basetime
);
1750 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1751 sfinfo
.generic
.in
.file
.fnum
= fnum
;
1752 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
1753 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1754 printf("(%s) %s - %s (should be %s)\n", __location__
, "SETATTR",
1755 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1760 smbcli_close(cli
->tree
, fnum
);
1764 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
1765 finfo
.generic
.in
.file
.path
= fname
;
1766 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1767 if (!NT_STATUS_IS_OK(status
)) {
1768 printf("(%s) %s pathinfo - %s\n", __location__
, "SETATTRE", nt_errstr(status
));
1773 if (finfo
.all_info
.out
.attrib
!= FILE_ATTRIBUTE_READONLY
) {
1774 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1776 (unsigned int)finfo
.all_info
.out
.attrib
,
1777 (unsigned int)FILE_ATTRIBUTE_READONLY
);
1782 if (nt_time_to_unix(finfo
.all_info
.out
.write_time
) != basetime
) {
1783 printf("(%s) time incorrect.\n",
1792 smbcli_close(cli
->tree
, fnum
);
1794 smbcli_unlink(cli
->tree
, fname
);
1795 smbcli_deltree(cli
->tree
, BASEDIR
);
1800 * A rough approximation of how a windows client creates the streams for use
1801 * in the summary tab.
1803 static bool test_stream_summary_tab(struct torture_context
*tctx
,
1804 struct smbcli_state
*cli
)
1809 const char *fname
= BASEDIR
"\\stream_summary.txt";
1810 const char *stream
= ":\005SummaryInformation:$DATA";
1811 const char *fname_stream
= NULL
;
1812 const char *tmp_stream
= ":Updt_\005SummaryInformation:$DATA";
1813 const char *fname_tmp_stream
= NULL
;
1815 union smb_fileinfo finfo
;
1816 union smb_rename rio
;
1819 if (!torture_setup_dir(cli
, BASEDIR
)) {
1823 fname_stream
= talloc_asprintf(tctx
, "%s%s", fname
, stream
);
1824 fname_tmp_stream
= talloc_asprintf(tctx
, "%s%s", fname
,
1827 /* Create summary info stream */
1828 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1833 /* Create summary info tmp update stream */
1834 ret
= create_file_with_stream(tctx
, cli
, fname_tmp_stream
);
1839 /* Open tmp stream and write to it */
1840 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1841 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1842 io
.ntcreatex
.in
.flags
= 0;
1843 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
1844 io
.ntcreatex
.in
.create_options
= 0;
1845 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1846 io
.ntcreatex
.in
.share_access
= 0;
1847 io
.ntcreatex
.in
.alloc_size
= 0;
1848 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1849 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1850 io
.ntcreatex
.in
.security_flags
= 0;
1851 io
.ntcreatex
.in
.fname
= fname_tmp_stream
;
1853 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1854 CHECK_STATUS(status
, NT_STATUS_OK
);
1855 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1857 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
1858 CHECK_VALUE(retsize
, 9);
1860 /* close the tmp stream. */
1861 smbcli_close(cli
->tree
, fnum
);
1864 /* Delete the current stream */
1865 smbcli_unlink(cli
->tree
, fname_stream
);
1867 /* Do the rename. */
1868 rio
.generic
.level
= RAW_RENAME_RENAME
;
1869 rio
.rename
.in
.pattern1
= fname_tmp_stream
;
1870 rio
.rename
.in
.pattern2
= stream
;
1871 rio
.rename
.in
.attrib
= FILE_ATTRIBUTE_SYSTEM
|
1872 FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
;
1873 status
= smb_raw_rename(cli
->tree
, &rio
);
1874 CHECK_STATUS(status
, NT_STATUS_OK
);
1876 /* Try to open the tmp stream that we just renamed away. */
1877 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1878 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1880 /* Query the base file to make sure it's still there. */
1881 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1882 finfo
.generic
.in
.file
.path
= fname
;
1884 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1885 CHECK_STATUS(status
, NT_STATUS_OK
);
1890 smbcli_close(cli
->tree
, fnum
);
1892 smbcli_unlink(cli
->tree
, fname
);
1894 smbcli_deltree(cli
->tree
, BASEDIR
);
1899 basic testing of streams calls
1901 struct torture_suite
*torture_raw_streams(TALLOC_CTX
*tctx
)
1903 struct torture_suite
*suite
= torture_suite_create(tctx
, "STREAMS");
1905 torture_suite_add_1smb_test(suite
, "DIR", test_stream_dir
);
1906 torture_suite_add_1smb_test(suite
, "IO", test_stream_io
);
1907 torture_suite_add_1smb_test(suite
, "SHAREMODES",
1908 test_stream_sharemodes
);
1909 torture_suite_add_1smb_test(suite
, "DELETE", test_stream_delete
);
1910 torture_suite_add_1smb_test(suite
, "NAMES", test_stream_names
);
1911 torture_suite_add_1smb_test(suite
, "NAMES2", test_stream_names2
);
1912 torture_suite_add_1smb_test(suite
, "RENAME", test_stream_rename
);
1913 torture_suite_add_1smb_test(suite
, "RENAME2", test_stream_rename2
);
1914 torture_suite_add_1smb_test(suite
, "RENAME3", test_stream_rename3
);
1915 torture_suite_add_1smb_test(suite
, "CREATEDISP",
1916 test_stream_create_disposition
);
1917 torture_suite_add_1smb_test(suite
, "ATTR", test_stream_attributes
);
1918 torture_suite_add_1smb_test(suite
, "SUMTAB", test_stream_summary_tab
);
1920 /* torture_suite_add_1smb_test(suite, "LARGESTREAMINFO", */
1921 /* test_stream_large_streaminfo); */