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"
29 #include "lib/util/tsort.h"
31 #define BASEDIR "\\teststreams"
33 #define CHECK_STATUS(status, correct) \
34 torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
36 #define CHECK_VALUE(v, correct) \
37 torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
39 #define CHECK_NTTIME(v, correct) \
40 torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
42 #define CHECK_STR(v, correct) do { \
44 if ((v) && !(correct)) { \
46 } else if (!(v) && (correct)) { \
48 } else if (!(v) && !(correct)) { \
50 } else if (strcmp((v), (correct)) == 0) { \
55 torture_assert(tctx,ok,\
56 talloc_asprintf(tctx, "got '%s', expected '%s'",\
57 (v)?(v):"NULL", (correct)?(correct):"NULL")); \
61 check that a stream has the right contents
63 static bool check_stream(struct smbcli_state
*cli
, const char *location
,
65 const char *fname
, const char *sname
,
69 const char *full_name
;
73 full_name
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, sname
);
75 fnum
= smbcli_open(cli
->tree
, full_name
, O_RDONLY
, DENY_NONE
);
79 printf("(%s) should have failed stream open of %s\n",
87 printf("(%s) Failed to open stream '%s' - %s\n",
88 location
, full_name
, smbcli_errstr(cli
->tree
));
92 buf
= talloc_array(mem_ctx
, uint8_t, strlen(value
)+11);
94 ret
= smbcli_read(cli
->tree
, fnum
, buf
, 0, strlen(value
)+11);
95 if (ret
!= strlen(value
)) {
96 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
97 location
, (long)strlen(value
), full_name
, (int)ret
);
101 if (memcmp(buf
, value
, strlen(value
)) != 0) {
102 printf("(%s) Bad data in stream\n", location
);
106 smbcli_close(cli
->tree
, fnum
);
110 static int qsort_string(char * const *s1
, char * const *s2
)
112 return strcmp(*s1
, *s2
);
115 static int qsort_stream(const struct stream_struct
*s1
, const struct stream_struct
*s2
)
117 return strcmp(s1
->stream_name
.s
, s2
->stream_name
.s
);
120 static bool check_stream_list(struct torture_context
*tctx
,
121 struct smbcli_state
*cli
, const char *fname
,
122 int num_exp
, const char **exp
)
124 union smb_fileinfo finfo
;
127 TALLOC_CTX
*tmp_ctx
= talloc_new(cli
);
129 struct stream_struct
*stream_sort
;
133 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
134 finfo
.generic
.in
.file
.path
= fname
;
136 status
= smb_raw_pathinfo(cli
->tree
, tmp_ctx
, &finfo
);
137 CHECK_STATUS(status
, NT_STATUS_OK
);
139 CHECK_VALUE(finfo
.stream_info
.out
.num_streams
, num_exp
);
146 exp_sort
= (char **)talloc_memdup(tmp_ctx
, exp
, num_exp
* sizeof(*exp
));
148 if (exp_sort
== NULL
) {
152 TYPESAFE_QSORT(exp_sort
, num_exp
, qsort_string
);
154 stream_sort
= (struct stream_struct
*)talloc_memdup(tmp_ctx
,
155 finfo
.stream_info
.out
.streams
,
156 finfo
.stream_info
.out
.num_streams
*
157 sizeof(*stream_sort
));
159 if (stream_sort
== NULL
) {
163 TYPESAFE_QSORT(stream_sort
, finfo
.stream_info
.out
.num_streams
, qsort_stream
);
165 for (i
=0; i
<num_exp
; i
++) {
166 if (strcmp(exp_sort
[i
], stream_sort
[i
].stream_name
.s
) != 0) {
174 talloc_free(tmp_ctx
);
178 for (i
=0; i
<num_exp
; i
++) {
179 torture_comment(tctx
, "stream names '%s' '%s'\n",
180 exp_sort
[i
], stream_sort
[i
].stream_name
.s
);
182 CHECK_STR(stream_sort
[fail
].stream_name
.s
, exp_sort
[fail
]);
183 talloc_free(tmp_ctx
);
188 test bahavior of streams on directories
190 static bool test_stream_dir(struct torture_context
*tctx
,
191 struct smbcli_state
*cli
)
195 const char *fname
= BASEDIR
"\\stream.txt";
198 const char *basedir_data
;
200 if (!torture_setup_dir(cli
, BASEDIR
)) {
204 basedir_data
= talloc_asprintf(tctx
, "%s::$DATA", BASEDIR
);
205 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
207 printf("(%s) opening non-existant directory stream\n", __location__
);
208 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
209 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
210 io
.ntcreatex
.in
.flags
= 0;
211 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
212 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
213 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
214 io
.ntcreatex
.in
.share_access
= 0;
215 io
.ntcreatex
.in
.alloc_size
= 0;
216 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
217 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
218 io
.ntcreatex
.in
.security_flags
= 0;
219 io
.ntcreatex
.in
.fname
= sname1
;
220 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
221 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
223 printf("(%s) opening basedir stream\n", __location__
);
224 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
225 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
226 io
.ntcreatex
.in
.flags
= 0;
227 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
228 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
229 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_DIRECTORY
;
230 io
.ntcreatex
.in
.share_access
= 0;
231 io
.ntcreatex
.in
.alloc_size
= 0;
232 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
233 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
234 io
.ntcreatex
.in
.security_flags
= 0;
235 io
.ntcreatex
.in
.fname
= basedir_data
;
236 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
237 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
239 printf("(%s) opening basedir ::$DATA stream\n", __location__
);
240 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
241 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
242 io
.ntcreatex
.in
.flags
= 0x10;
243 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
244 io
.ntcreatex
.in
.create_options
= 0;
245 io
.ntcreatex
.in
.file_attr
= 0;
246 io
.ntcreatex
.in
.share_access
= 0;
247 io
.ntcreatex
.in
.alloc_size
= 0;
248 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
249 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
250 io
.ntcreatex
.in
.security_flags
= 0;
251 io
.ntcreatex
.in
.fname
= basedir_data
;
252 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
253 CHECK_STATUS(status
, NT_STATUS_FILE_IS_A_DIRECTORY
);
255 printf("(%s) list the streams on the basedir\n", __location__
);
256 ret
&= check_stream_list(tctx
, cli
, BASEDIR
, 0, NULL
);
258 smbcli_deltree(cli
->tree
, BASEDIR
);
263 test basic behavior of streams on directories
265 static bool test_stream_io(struct torture_context
*tctx
,
266 struct smbcli_state
*cli
)
270 const char *fname
= BASEDIR
"\\stream.txt";
271 const char *sname1
, *sname2
;
276 const char *one
[] = { "::$DATA" };
277 const char *two
[] = { "::$DATA", ":Second Stream:$DATA" };
278 const char *three
[] = { "::$DATA", ":Stream One:$DATA",
279 ":Second Stream:$DATA" };
281 if (!torture_setup_dir(cli
, BASEDIR
)) {
285 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
286 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
288 printf("(%s) creating a stream on a non-existant file\n", __location__
);
289 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
290 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
291 io
.ntcreatex
.in
.flags
= 0;
292 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
293 io
.ntcreatex
.in
.create_options
= 0;
294 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
295 io
.ntcreatex
.in
.share_access
= 0;
296 io
.ntcreatex
.in
.alloc_size
= 0;
297 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
298 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
299 io
.ntcreatex
.in
.security_flags
= 0;
300 io
.ntcreatex
.in
.fname
= sname1
;
301 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
302 CHECK_STATUS(status
, NT_STATUS_OK
);
303 fnum
= io
.ntcreatex
.out
.file
.fnum
;
305 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", NULL
);
307 printf("(%s) check that open of base file is allowed\n", __location__
);
308 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
309 io
.ntcreatex
.in
.fname
= fname
;
310 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
311 CHECK_STATUS(status
, NT_STATUS_OK
);
312 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
314 printf("(%s) writing to stream\n", __location__
);
315 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
316 CHECK_VALUE(retsize
, 9);
318 smbcli_close(cli
->tree
, fnum
);
320 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test data");
322 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
323 io
.ntcreatex
.in
.fname
= sname1
;
324 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
325 CHECK_STATUS(status
, NT_STATUS_OK
);
326 fnum
= io
.ntcreatex
.out
.file
.fnum
;
328 printf("(%s) modifying stream\n", __location__
);
329 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "MORE DATA ", 5, 10);
330 CHECK_VALUE(retsize
, 10);
332 smbcli_close(cli
->tree
, fnum
);
334 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$FOO", NULL
);
336 printf("(%s) creating a stream2 on a existing file\n", __location__
);
337 io
.ntcreatex
.in
.fname
= sname2
;
338 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
339 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
340 CHECK_STATUS(status
, NT_STATUS_OK
);
341 fnum
= io
.ntcreatex
.out
.file
.fnum
;
343 printf("(%s) modifying stream\n", __location__
);
344 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "SECOND STREAM", 0, 13);
345 CHECK_VALUE(retsize
, 13);
347 smbcli_close(cli
->tree
, fnum
);
349 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test MORE DATA ");
350 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$DATA", "test MORE DATA ");
351 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:", NULL
);
352 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream", "SECOND STREAM");
353 ret
&= check_stream(cli
, __location__
, tctx
, fname
,
354 "SECOND STREAM:$DATA", "SECOND STREAM");
355 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$DATA", "SECOND STREAM");
356 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:", NULL
);
357 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$FOO", NULL
);
359 check_stream_list(tctx
, cli
, fname
, 3, three
);
361 printf("(%s) deleting stream\n", __location__
);
362 status
= smbcli_unlink(cli
->tree
, sname1
);
363 CHECK_STATUS(status
, NT_STATUS_OK
);
365 check_stream_list(tctx
, cli
, fname
, 2, two
);
367 printf("(%s) delete a stream via delete-on-close\n", __location__
);
368 io
.ntcreatex
.in
.fname
= sname2
;
369 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
370 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
371 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
372 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
374 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
375 CHECK_STATUS(status
, NT_STATUS_OK
);
376 fnum
= io
.ntcreatex
.out
.file
.fnum
;
378 smbcli_close(cli
->tree
, fnum
);
379 status
= smbcli_unlink(cli
->tree
, sname2
);
380 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
382 check_stream_list(tctx
, cli
, fname
, 1, one
);
384 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
385 io
.ntcreatex
.in
.fname
= sname1
;
386 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
387 CHECK_STATUS(status
, NT_STATUS_OK
);
388 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
389 io
.ntcreatex
.in
.fname
= sname2
;
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
);
394 printf("(%s) deleting file\n", __location__
);
395 status
= smbcli_unlink(cli
->tree
, fname
);
396 CHECK_STATUS(status
, NT_STATUS_OK
);
399 smbcli_close(cli
->tree
, fnum
);
400 smbcli_deltree(cli
->tree
, BASEDIR
);
405 test stream sharemodes
407 static bool test_stream_sharemodes(struct torture_context
*tctx
,
408 struct smbcli_state
*cli
)
412 const char *fname
= BASEDIR
"\\stream.txt";
413 const char *sname1
, *sname2
;
418 if (!torture_setup_dir(cli
, BASEDIR
)) {
422 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
423 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
425 printf("(%s) testing stream share mode conflicts\n", __location__
);
426 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
427 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
428 io
.ntcreatex
.in
.flags
= 0;
429 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
430 io
.ntcreatex
.in
.create_options
= 0;
431 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
432 io
.ntcreatex
.in
.share_access
= 0;
433 io
.ntcreatex
.in
.alloc_size
= 0;
434 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
435 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
436 io
.ntcreatex
.in
.security_flags
= 0;
437 io
.ntcreatex
.in
.fname
= sname1
;
439 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
440 CHECK_STATUS(status
, NT_STATUS_OK
);
441 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
444 * A different stream does not give a sharing violation
447 io
.ntcreatex
.in
.fname
= sname2
;
448 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
449 CHECK_STATUS(status
, NT_STATUS_OK
);
450 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
453 * ... whereas the same stream does with unchanged access/share_access
457 io
.ntcreatex
.in
.fname
= sname1
;
458 io
.ntcreatex
.in
.open_disposition
= 0;
459 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
460 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
462 io
.ntcreatex
.in
.fname
= sname2
;
463 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
464 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
467 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
468 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
469 status
= smbcli_unlink(cli
->tree
, fname
);
470 smbcli_deltree(cli
->tree
, BASEDIR
);
475 * Test FILE_SHARE_DELETE on streams
477 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
478 * with SEC_STD_DELETE.
480 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
481 * be opened with SEC_STD_DELETE.
483 * A stream held open with FILE_SHARE_DELETE allows the file to be
484 * deleted. After the main file is deleted, access to the open file descriptor
485 * still works, but all name-based access to both the main file as well as the
486 * stream is denied with DELETE ending.
488 * This means, an open of the main file with SEC_STD_DELETE should walk all
489 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
490 * SHARING_VIOLATION, the main open fails.
492 * Closing the main file after delete_on_close has been set does not really
493 * unlink it but leaves the corresponding share mode entry with
494 * delete_on_close being set around until all streams are closed.
496 * Opening a stream must also look at the main file's share mode entry, look
497 * at the delete_on_close bit and potentially return DELETE_PENDING.
500 static bool test_stream_delete(struct torture_context
*tctx
,
501 struct smbcli_state
*cli
)
505 const char *fname
= BASEDIR
"\\stream.txt";
511 union smb_fileinfo finfo
;
513 if (!torture_setup_dir(cli
, BASEDIR
)) {
517 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
519 printf("(%s) opening non-existant file stream\n", __location__
);
520 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
521 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
522 io
.ntcreatex
.in
.flags
= 0;
523 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
524 io
.ntcreatex
.in
.create_options
= 0;
525 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
526 io
.ntcreatex
.in
.share_access
= 0;
527 io
.ntcreatex
.in
.alloc_size
= 0;
528 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
529 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
530 io
.ntcreatex
.in
.security_flags
= 0;
531 io
.ntcreatex
.in
.fname
= sname1
;
533 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
534 CHECK_STATUS(status
, NT_STATUS_OK
);
535 fnum
= io
.ntcreatex
.out
.file
.fnum
;
537 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
538 CHECK_VALUE(retsize
, 9);
541 * One stream opened without FILE_SHARE_DELETE prevents the main file
542 * to be deleted or even opened with DELETE access
545 status
= smbcli_unlink(cli
->tree
, fname
);
546 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
548 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
549 io
.ntcreatex
.in
.fname
= fname
;
550 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
551 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
552 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
554 smbcli_close(cli
->tree
, fnum
);
557 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
560 io
.ntcreatex
.in
.fname
= sname1
;
561 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
562 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
563 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
564 CHECK_STATUS(status
, NT_STATUS_OK
);
565 fnum
= io
.ntcreatex
.out
.file
.fnum
;
567 status
= smbcli_unlink(cli
->tree
, fname
);
568 CHECK_STATUS(status
, NT_STATUS_OK
);
571 * file access still works on the stream while the main file is closed
574 retsize
= smbcli_read(cli
->tree
, fnum
, buf
, 0, 9);
575 CHECK_VALUE(retsize
, 9);
577 finfo
.generic
.level
= RAW_FILEINFO_STANDARD
;
578 finfo
.generic
.in
.file
.path
= fname
;
581 * name-based access to both the main file and the stream does not
582 * work anymore but gives DELETE_PENDING
585 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
586 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
589 * older S3 doesn't do this
591 finfo
.generic
.in
.file
.path
= sname1
;
592 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
593 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
596 * fd-based qfileinfo on the stream still works, the stream does not
597 * have the delete-on-close bit set. This could mean that open on the
598 * stream first opens the main file
601 finfo
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
602 finfo
.all_info
.in
.file
.fnum
= fnum
;
604 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo
);
605 CHECK_STATUS(status
, NT_STATUS_OK
);
607 /* w2k and w2k3 return 0 and w2k8 returns 1 */
608 if (TARGET_IS_WINXP(tctx
) || TARGET_IS_W2K3(tctx
) ||
609 TARGET_IS_SAMBA3(tctx
)) {
610 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 0);
612 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 1);
615 smbcli_close(cli
->tree
, fnum
);
618 * After closing the stream the file is really gone.
621 finfo
.generic
.in
.file
.path
= fname
;
622 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
623 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
625 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
627 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
628 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
629 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
630 CHECK_STATUS(status
, NT_STATUS_OK
);
631 fnum
= io
.ntcreatex
.out
.file
.fnum
;
633 finfo
.generic
.in
.file
.path
= fname
;
634 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
635 CHECK_STATUS(status
, NT_STATUS_OK
);
637 smbcli_close(cli
->tree
, fnum
);
639 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
640 CHECK_STATUS(status
, NT_STATUS_OK
);
642 smbcli_close(cli
->tree
, fnum
);
643 smbcli_unlink(cli
->tree
, fname
);
644 smbcli_deltree(cli
->tree
, BASEDIR
);
651 static bool test_stream_names(struct torture_context
*tctx
,
652 struct smbcli_state
*cli
)
656 union smb_fileinfo finfo
;
657 union smb_fileinfo stinfo
;
658 union smb_setfileinfo sinfo
;
659 const char *fname
= BASEDIR
"\\stream_names.txt";
660 const char *sname1
, *sname1b
, *sname1c
, *sname1d
;
661 const char *sname2
, *snamew
, *snamew2
;
662 const char *snamer1
, *snamer2
;
668 const char *four
[4] = {
670 ":\x05Stream\n One:$DATA",
671 ":MStream Two:$DATA",
674 const char *five1
[5] = {
676 ":\x05Stream\n One:$DATA",
677 ":BeforeRename:$DATA",
678 ":MStream Two:$DATA",
681 const char *five2
[5] = {
683 ":\x05Stream\n One:$DATA",
684 ":AfterRename:$DATA",
685 ":MStream Two:$DATA",
689 if (!torture_setup_dir(cli
, BASEDIR
)) {
693 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "\x05Stream\n One");
694 sname1b
= talloc_asprintf(tctx
, "%s:", sname1
);
695 sname1c
= talloc_asprintf(tctx
, "%s:$FOO", sname1
);
696 sname1d
= talloc_asprintf(tctx
, "%s:?D*a", sname1
);
697 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "MStream Two");
698 snamew
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "?Stream*");
699 snamew2
= talloc_asprintf(tctx
, "%s\\stream*:%s:$DATA", BASEDIR
, "?Stream*");
700 snamer1
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "BeforeRename");
701 snamer2
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "AfterRename");
703 printf("(%s) testing stream names\n", __location__
);
704 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
705 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
706 io
.ntcreatex
.in
.flags
= 0;
707 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
708 io
.ntcreatex
.in
.create_options
= 0;
709 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
710 io
.ntcreatex
.in
.share_access
= 0;
711 io
.ntcreatex
.in
.alloc_size
= 0;
712 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
713 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
714 io
.ntcreatex
.in
.security_flags
= 0;
715 io
.ntcreatex
.in
.fname
= fname
;
717 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
718 CHECK_STATUS(status
, NT_STATUS_OK
);
719 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
722 * Make sure the create time of the streams are different from the
726 smbcli_close(cli
->tree
, fnum1
);
728 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
729 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
730 io
.ntcreatex
.in
.flags
= 0;
731 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
732 io
.ntcreatex
.in
.create_options
= 0;
733 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
734 io
.ntcreatex
.in
.share_access
= 0;
735 io
.ntcreatex
.in
.alloc_size
= 0;
736 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
737 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
738 io
.ntcreatex
.in
.security_flags
= 0;
739 io
.ntcreatex
.in
.fname
= sname1
;
741 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
742 CHECK_STATUS(status
, NT_STATUS_OK
);
743 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
746 * A different stream does not give a sharing violation
749 io
.ntcreatex
.in
.fname
= sname2
;
750 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
751 CHECK_STATUS(status
, NT_STATUS_OK
);
752 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
755 * ... whereas the same stream does with unchanged access/share_access
759 io
.ntcreatex
.in
.fname
= sname1
;
760 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
761 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
762 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
764 io
.ntcreatex
.in
.fname
= sname1b
;
765 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
766 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
768 io
.ntcreatex
.in
.fname
= sname1c
;
769 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
770 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
771 /* w2k returns INVALID_PARAMETER */
772 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
774 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
777 io
.ntcreatex
.in
.fname
= sname1d
;
778 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
779 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
780 /* w2k returns INVALID_PARAMETER */
781 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
783 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
786 io
.ntcreatex
.in
.fname
= sname2
;
787 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
788 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
790 io
.ntcreatex
.in
.fname
= snamew
;
791 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
792 CHECK_STATUS(status
, NT_STATUS_OK
);
793 fnum3
= io
.ntcreatex
.out
.file
.fnum
;
795 io
.ntcreatex
.in
.fname
= snamew2
;
796 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
797 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
799 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
801 smbcli_close(cli
->tree
, fnum1
);
802 smbcli_close(cli
->tree
, fnum2
);
803 smbcli_close(cli
->tree
, fnum3
);
805 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
806 finfo
.generic
.in
.file
.path
= fname
;
807 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
808 CHECK_STATUS(status
, NT_STATUS_OK
);
810 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
812 for (i
=0; i
< 4; i
++) {
814 uint64_t stream_size
;
815 char *path
= talloc_asprintf(tctx
, "%s%s",
818 char *rpath
= talloc_strdup(path
, path
);
819 char *p
= strrchr(rpath
, ':');
827 printf("(%s): i[%u][%s]\n", __location__
, i
, path
);
828 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
829 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
830 SEC_FILE_WRITE_ATTRIBUTE
|
832 io
.ntcreatex
.in
.fname
= path
;
833 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
834 CHECK_STATUS(status
, NT_STATUS_OK
);
835 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
837 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
838 finfo
.generic
.in
.file
.path
= fname
;
839 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
840 CHECK_STATUS(status
, NT_STATUS_OK
);
842 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
843 stinfo
.generic
.in
.file
.fnum
= fnum1
;
844 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
845 CHECK_STATUS(status
, NT_STATUS_OK
);
846 if (!torture_setting_bool(tctx
, "samba3", false)) {
847 CHECK_NTTIME(stinfo
.all_info
.out
.create_time
,
848 finfo
.all_info
.out
.create_time
);
849 CHECK_NTTIME(stinfo
.all_info
.out
.access_time
,
850 finfo
.all_info
.out
.access_time
);
851 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
852 finfo
.all_info
.out
.write_time
);
853 CHECK_NTTIME(stinfo
.all_info
.out
.change_time
,
854 finfo
.all_info
.out
.change_time
);
856 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
857 finfo
.all_info
.out
.attrib
);
858 CHECK_VALUE(stinfo
.all_info
.out
.size
,
859 finfo
.all_info
.out
.size
);
860 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
861 finfo
.all_info
.out
.delete_pending
);
862 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
863 finfo
.all_info
.out
.directory
);
864 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
865 finfo
.all_info
.out
.ea_size
);
867 stinfo
.generic
.level
= RAW_FILEINFO_NAME_INFO
;
868 stinfo
.generic
.in
.file
.fnum
= fnum1
;
869 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
870 CHECK_STATUS(status
, NT_STATUS_OK
);
871 if (!torture_setting_bool(tctx
, "samba3", false)) {
872 CHECK_STR(stinfo
.name_info
.out
.fname
.s
, rpath
);
875 write_time
= finfo
.all_info
.out
.write_time
;
876 write_time
+= i
*1000000;
877 write_time
/= 1000000;
878 write_time
*= 1000000;
881 sinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
882 sinfo
.basic_info
.in
.file
.fnum
= fnum1
;
883 sinfo
.basic_info
.in
.write_time
= write_time
;
884 sinfo
.basic_info
.in
.attrib
= stinfo
.all_info
.out
.attrib
;
885 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
886 CHECK_STATUS(status
, NT_STATUS_OK
);
888 stream_size
= i
*8192;
891 sinfo
.end_of_file_info
.level
= RAW_SFILEINFO_END_OF_FILE_INFO
;
892 sinfo
.end_of_file_info
.in
.file
.fnum
= fnum1
;
893 sinfo
.end_of_file_info
.in
.size
= stream_size
;
894 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
895 CHECK_STATUS(status
, NT_STATUS_OK
);
897 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
898 stinfo
.generic
.in
.file
.fnum
= fnum1
;
899 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
900 CHECK_STATUS(status
, NT_STATUS_OK
);
901 if (!torture_setting_bool(tctx
, "samba3", false)) {
902 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
904 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
905 finfo
.all_info
.out
.attrib
);
907 CHECK_VALUE(stinfo
.all_info
.out
.size
,
909 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
910 finfo
.all_info
.out
.delete_pending
);
911 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
912 finfo
.all_info
.out
.directory
);
913 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
914 finfo
.all_info
.out
.ea_size
);
916 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
918 smbcli_close(cli
->tree
, fnum1
);
922 printf("(%s): testing stream renames\n", __location__
);
923 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
924 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
925 SEC_FILE_WRITE_ATTRIBUTE
|
927 io
.ntcreatex
.in
.fname
= snamer1
;
928 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
929 CHECK_STATUS(status
, NT_STATUS_OK
);
930 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
932 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five1
);
935 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
936 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
937 sinfo
.rename_information
.in
.overwrite
= true;
938 sinfo
.rename_information
.in
.root_fid
= 0;
939 sinfo
.rename_information
.in
.new_name
= ":AfterRename:$DATA";
940 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
941 CHECK_STATUS(status
, NT_STATUS_OK
);
943 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
946 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
947 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
948 sinfo
.rename_information
.in
.overwrite
= false;
949 sinfo
.rename_information
.in
.root_fid
= 0;
950 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
951 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
952 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
954 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
957 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
958 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
959 sinfo
.rename_information
.in
.overwrite
= true;
960 sinfo
.rename_information
.in
.root_fid
= 0;
961 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
962 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
963 if (torture_setting_bool(tctx
, "samba4", false) ||
964 torture_setting_bool(tctx
, "samba3", false)) {
965 /* why should this rename be considered invalid?? */
966 CHECK_STATUS(status
, NT_STATUS_OK
);
967 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
969 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
970 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
974 /* TODO: we need to test more rename combinations */
977 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
978 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
979 if (fnum3
!= -1) smbcli_close(cli
->tree
, fnum3
);
980 status
= smbcli_unlink(cli
->tree
, fname
);
981 smbcli_deltree(cli
->tree
, BASEDIR
);
988 static bool test_stream_names2(struct torture_context
*tctx
,
989 struct smbcli_state
*cli
)
993 const char *fname
= BASEDIR
"\\stream_names2.txt";
998 if (!torture_setup_dir(cli
, BASEDIR
)) {
1002 printf("(%s) testing stream names\n", __location__
);
1003 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1004 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1005 io
.ntcreatex
.in
.flags
= 0;
1006 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
1007 io
.ntcreatex
.in
.create_options
= 0;
1008 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1009 io
.ntcreatex
.in
.share_access
= 0;
1010 io
.ntcreatex
.in
.alloc_size
= 0;
1011 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1012 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1013 io
.ntcreatex
.in
.security_flags
= 0;
1014 io
.ntcreatex
.in
.fname
= fname
;
1015 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1016 CHECK_STATUS(status
, NT_STATUS_OK
);
1017 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
1019 for (i
=0x01; i
< 0x7F; i
++) {
1020 char *path
= talloc_asprintf(tctx
, "%s:Stream%c0x%02X:$DATA",
1028 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1031 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1036 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1037 io
.ntcreatex
.in
.fname
= path
;
1038 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1039 if (!NT_STATUS_EQUAL(status
, expected
)) {
1040 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1041 __location__
, fname
, isprint(i
)?(char)i
:' ', i
,
1042 isprint(i
)?"":" (not printable)",
1043 nt_errstr(expected
));
1045 CHECK_STATUS(status
, expected
);
1051 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
1052 status
= smbcli_unlink(cli
->tree
, fname
);
1053 smbcli_deltree(cli
->tree
, BASEDIR
);
1057 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1058 check_fnum = true; \
1059 call_name = #call; \
1060 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1061 sfinfo.generic.in.file.fnum = fnum; \
1062 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1063 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1064 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1065 nt_errstr(status), nt_errstr(rightstatus)); \
1068 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1069 finfo1.generic.in.file.fnum = fnum; \
1070 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1071 if (!NT_STATUS_IS_OK(status2)) { \
1072 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1079 static bool test_stream_rename(struct torture_context
*tctx
,
1080 struct smbcli_state
*cli
)
1082 NTSTATUS status
, status2
;
1084 const char *fname
= BASEDIR
"\\stream_rename.txt";
1085 const char *sname1
, *sname2
;
1086 union smb_fileinfo finfo1
;
1087 union smb_setfileinfo sfinfo
;
1091 const char *call_name
;
1093 if (!torture_setup_dir(cli
, BASEDIR
)) {
1097 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
1098 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1100 printf("(%s) testing stream renames\n", __location__
);
1101 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1102 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1103 io
.ntcreatex
.in
.flags
= 0;
1104 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1105 SEC_FILE_WRITE_ATTRIBUTE
|
1106 SEC_RIGHTS_FILE_ALL
;
1107 io
.ntcreatex
.in
.create_options
= 0;
1108 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1109 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1110 io
.ntcreatex
.in
.alloc_size
= 0;
1111 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1112 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1113 io
.ntcreatex
.in
.security_flags
= 0;
1114 io
.ntcreatex
.in
.fname
= sname1
;
1116 /* Create two streams. */
1117 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1118 CHECK_STATUS(status
, NT_STATUS_OK
);
1119 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1120 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1122 io
.ntcreatex
.in
.fname
= sname2
;
1123 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1124 CHECK_STATUS(status
, NT_STATUS_OK
);
1125 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1127 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1130 * Open the second stream.
1133 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1134 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1135 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1136 CHECK_STATUS(status
, NT_STATUS_OK
);
1137 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1140 * Now rename the second stream onto the first.
1143 ZERO_STRUCT(sfinfo
);
1145 sfinfo
.rename_information
.in
.overwrite
= 1;
1146 sfinfo
.rename_information
.in
.root_fid
= 0;
1147 sfinfo
.rename_information
.in
.new_name
= ":Stream One";
1148 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1151 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1152 status
= smbcli_unlink(cli
->tree
, fname
);
1153 smbcli_deltree(cli
->tree
, BASEDIR
);
1157 static bool test_stream_rename2(struct torture_context
*tctx
,
1158 struct smbcli_state
*cli
)
1162 const char *fname1
= BASEDIR
"\\stream.txt";
1163 const char *fname2
= BASEDIR
"\\stream2.txt";
1164 const char *stream_name1
= ":Stream One:$DATA";
1165 const char *stream_name2
= ":Stream Two:$DATA";
1166 const char *stream_name_default
= "::$DATA";
1171 union smb_setfileinfo sinfo
;
1172 union smb_rename rio
;
1174 if (!torture_setup_dir(cli
, BASEDIR
)) {
1178 sname1
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream One");
1179 sname2
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream Two");
1181 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1182 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1183 io
.ntcreatex
.in
.flags
= 0;
1184 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1185 SEC_STD_DELETE
|SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1186 io
.ntcreatex
.in
.create_options
= 0;
1187 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1188 io
.ntcreatex
.in
.share_access
= (NTCREATEX_SHARE_ACCESS_READ
|
1189 NTCREATEX_SHARE_ACCESS_WRITE
|
1190 NTCREATEX_SHARE_ACCESS_DELETE
);
1191 io
.ntcreatex
.in
.alloc_size
= 0;
1192 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1193 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1194 io
.ntcreatex
.in
.security_flags
= 0;
1195 io
.ntcreatex
.in
.fname
= sname1
;
1197 /* Open/create new stream. */
1198 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1199 CHECK_STATUS(status
, NT_STATUS_OK
);
1201 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1204 * Check raw rename with <base>:<stream>.
1206 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1208 rio
.generic
.level
= RAW_RENAME_NTRENAME
;
1209 rio
.ntrename
.in
.old_name
= sname1
;
1210 rio
.ntrename
.in
.new_name
= sname2
;
1211 rio
.ntrename
.in
.attrib
= 0;
1212 rio
.ntrename
.in
.cluster_size
= 0;
1213 rio
.ntrename
.in
.flags
= RENAME_FLAG_RENAME
;
1214 status
= smb_raw_rename(cli
->tree
, &rio
);
1215 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1218 * Check raw rename to the default stream using :<stream>.
1220 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1222 rio
.ntrename
.in
.new_name
= stream_name_default
;
1223 status
= smb_raw_rename(cli
->tree
, &rio
);
1224 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
1227 * Check raw rename using :<stream>.
1229 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1231 rio
.ntrename
.in
.new_name
= stream_name2
;
1232 status
= smb_raw_rename(cli
->tree
, &rio
);
1233 CHECK_STATUS(status
, NT_STATUS_OK
);
1236 * Check raw rename of a stream to a file.
1238 printf("(%s) Checking NTRENAME of a stream to a file\n",
1240 rio
.ntrename
.in
.old_name
= sname2
;
1241 rio
.ntrename
.in
.new_name
= fname2
;
1242 status
= smb_raw_rename(cli
->tree
, &rio
);
1243 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1246 * Check raw rename of a file to a stream.
1248 printf("(%s) Checking NTRENAME of a file to a stream\n",
1251 /* Create the file. */
1252 io
.ntcreatex
.in
.fname
= fname2
;
1253 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1254 CHECK_STATUS(status
, NT_STATUS_OK
);
1255 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1257 /* Try the rename. */
1258 rio
.ntrename
.in
.old_name
= fname2
;
1259 rio
.ntrename
.in
.new_name
= sname1
;
1260 status
= smb_raw_rename(cli
->tree
, &rio
);
1261 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
1264 * Reopen the stream for trans2 renames.
1266 io
.ntcreatex
.in
.fname
= sname2
;
1267 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1268 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1269 CHECK_STATUS(status
, NT_STATUS_OK
);
1270 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1273 * Check trans2 rename of a stream using :<stream>.
1275 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1278 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1279 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1280 sinfo
.rename_information
.in
.overwrite
= 1;
1281 sinfo
.rename_information
.in
.root_fid
= 0;
1282 sinfo
.rename_information
.in
.new_name
= stream_name1
;
1283 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1284 CHECK_STATUS(status
, NT_STATUS_OK
);
1287 * Check trans2 rename of an overwriting stream using :<stream>.
1289 printf("(%s) Checking trans2 rename of an overwriting stream using "
1290 ":<stream>\n", __location__
);
1292 /* Create second stream. */
1293 io
.ntcreatex
.in
.fname
= sname2
;
1294 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1295 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1296 CHECK_STATUS(status
, NT_STATUS_OK
);
1297 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1299 /* Rename the first stream onto the second. */
1300 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1301 sinfo
.rename_information
.in
.new_name
= stream_name2
;
1302 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1303 CHECK_STATUS(status
, NT_STATUS_OK
);
1305 smbcli_close(cli
->tree
, fnum
);
1308 * Reopen the stream with the new name.
1310 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1311 io
.ntcreatex
.in
.fname
= sname2
;
1312 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1313 CHECK_STATUS(status
, NT_STATUS_OK
);
1314 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1317 * Check trans2 rename of a stream using <base>:<stream>.
1319 printf("(%s) Checking trans2 rename of a stream using "
1320 "<base>:<stream>\n", __location__
);
1321 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1322 sinfo
.rename_information
.in
.new_name
= sname1
;
1323 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1324 CHECK_STATUS(status
, NT_STATUS_NOT_SUPPORTED
);
1327 * Samba3 doesn't currently support renaming a stream to the default
1328 * stream. This test does pass on windows.
1330 if (torture_setting_bool(tctx
, "samba3", false) ||
1331 torture_setting_bool(tctx
, "samba4", false)) {
1336 * Check trans2 rename to the default stream using :<stream>.
1338 printf("(%s) Checking trans2 rename to defaualt stream using "
1339 ":<stream>\n", __location__
);
1340 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1341 sinfo
.rename_information
.in
.new_name
= stream_name_default
;
1342 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1343 CHECK_STATUS(status
, NT_STATUS_OK
);
1345 smbcli_close(cli
->tree
, fnum
);
1348 smbcli_close(cli
->tree
, fnum
);
1349 status
= smbcli_unlink(cli
->tree
, fname1
);
1350 status
= smbcli_unlink(cli
->tree
, fname2
);
1351 smbcli_deltree(cli
->tree
, BASEDIR
);
1358 static bool test_stream_rename3(struct torture_context
*tctx
,
1359 struct smbcli_state
*cli
)
1361 NTSTATUS status
, status2
;
1363 const char *fname
= BASEDIR
"\\stream_rename.txt";
1364 const char *sname1
, *sname2
;
1365 union smb_fileinfo finfo1
;
1366 union smb_setfileinfo sfinfo
;
1371 const char *call_name
;
1373 if (!torture_setup_dir(cli
, BASEDIR
)) {
1377 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "MStream Two:$DATA");
1378 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1380 printf("(%s) testing stream renames\n", __location__
);
1381 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1382 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1383 io
.ntcreatex
.in
.flags
= 0;
1384 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1385 SEC_FILE_WRITE_ATTRIBUTE
|
1386 SEC_RIGHTS_FILE_ALL
;
1387 io
.ntcreatex
.in
.create_options
= 0;
1388 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1389 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1390 NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1391 io
.ntcreatex
.in
.alloc_size
= 0;
1392 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1393 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1394 io
.ntcreatex
.in
.security_flags
= 0;
1395 io
.ntcreatex
.in
.fname
= sname1
;
1397 /* Create two streams. */
1398 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1399 CHECK_STATUS(status
, NT_STATUS_OK
);
1400 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1401 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1403 io
.ntcreatex
.in
.fname
= sname2
;
1404 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1405 CHECK_STATUS(status
, NT_STATUS_OK
);
1406 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1408 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1410 /* open the second stream. */
1411 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1412 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1413 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1414 CHECK_STATUS(status
, NT_STATUS_OK
);
1415 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1417 /* Keep a handle to the first stream open. */
1418 io
.ntcreatex
.in
.fname
= sname1
;
1419 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1420 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1421 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1422 CHECK_STATUS(status
, NT_STATUS_OK
);
1423 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
1425 ZERO_STRUCT(sfinfo
);
1426 sfinfo
.rename_information
.in
.overwrite
= 1;
1427 sfinfo
.rename_information
.in
.root_fid
= 0;
1428 sfinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1429 if (torture_setting_bool(tctx
, "samba4", false) ||
1430 torture_setting_bool(tctx
, "samba3", false)) {
1431 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1433 CHECK_CALL_FNUM(RENAME_INFORMATION
,
1434 NT_STATUS_INVALID_PARAMETER
);
1439 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1440 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
1441 status
= smbcli_unlink(cli
->tree
, fname
);
1442 smbcli_deltree(cli
->tree
, BASEDIR
);
1446 static bool create_file_with_stream(struct torture_context
*tctx
,
1447 struct smbcli_state
*cli
,
1454 /* Create a file with a stream */
1455 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1456 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1457 io
.ntcreatex
.in
.flags
= 0;
1458 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1459 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1460 io
.ntcreatex
.in
.create_options
= 0;
1461 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1462 io
.ntcreatex
.in
.share_access
= 0;
1463 io
.ntcreatex
.in
.alloc_size
= 0;
1464 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1465 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1466 io
.ntcreatex
.in
.security_flags
= 0;
1467 io
.ntcreatex
.in
.fname
= stream
;
1469 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1470 CHECK_STATUS(status
, NT_STATUS_OK
);
1473 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1477 /* Test how streams interact with create dispositions */
1478 static bool test_stream_create_disposition(struct torture_context
*tctx
,
1479 struct smbcli_state
*cli
)
1483 const char *fname
= BASEDIR
"\\stream.txt";
1484 const char *stream
= "Stream One:$DATA";
1485 const char *fname_stream
;
1486 const char *default_stream_name
= "::$DATA";
1487 const char *stream_list
[2];
1491 if (!torture_setup_dir(cli
, BASEDIR
)) {
1495 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1497 stream_list
[0] = talloc_asprintf(tctx
, ":%s", stream
);
1498 stream_list
[1] = default_stream_name
;
1500 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1504 /* Open the base file with OPEN */
1505 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1506 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1507 io
.ntcreatex
.in
.flags
= 0;
1508 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1509 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1510 io
.ntcreatex
.in
.create_options
= 0;
1511 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1512 io
.ntcreatex
.in
.share_access
= 0;
1513 io
.ntcreatex
.in
.alloc_size
= 0;
1514 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1515 io
.ntcreatex
.in
.security_flags
= 0;
1516 io
.ntcreatex
.in
.fname
= fname
;
1519 * check ntcreatex open: sanity check
1521 printf("(%s) Checking ntcreatex disp: open\n", __location__
);
1522 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1523 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1524 CHECK_STATUS(status
, NT_STATUS_OK
);
1525 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1526 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1531 * check ntcreatex overwrite
1533 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__
);
1534 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
1535 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1536 CHECK_STATUS(status
, NT_STATUS_OK
);
1537 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1538 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1543 * check ntcreatex overwrite_if
1545 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__
);
1546 smbcli_unlink(cli
->tree
, fname
);
1547 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1551 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1552 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1553 CHECK_STATUS(status
, NT_STATUS_OK
);
1554 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1555 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1560 * check ntcreatex supersede
1562 printf("(%s) Checking ntcreatex disp: supersede\n", __location__
);
1563 smbcli_unlink(cli
->tree
, fname
);
1564 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1568 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
1569 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1570 CHECK_STATUS(status
, NT_STATUS_OK
);
1571 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1572 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1577 * check ntcreatex overwrite_if on a stream.
1579 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1581 smbcli_unlink(cli
->tree
, fname
);
1582 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1586 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1587 io
.ntcreatex
.in
.fname
= fname_stream
;
1588 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1589 CHECK_STATUS(status
, NT_STATUS_OK
);
1590 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1591 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1596 * check openx overwrite_if
1598 printf("(%s) Checking openx disp: overwrite_if\n", __location__
);
1599 smbcli_unlink(cli
->tree
, fname
);
1600 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1604 io
.openx
.level
= RAW_OPEN_OPENX
;
1605 io
.openx
.in
.flags
= OPENX_FLAGS_ADDITIONAL_INFO
;
1606 io
.openx
.in
.open_mode
= OPENX_MODE_ACCESS_RDWR
| OPEN_FLAGS_DENY_NONE
;
1607 io
.openx
.in
.search_attrs
= 0;
1608 io
.openx
.in
.file_attrs
= 0;
1609 io
.openx
.in
.write_time
= 0;
1610 io
.openx
.in
.size
= 1024*1024;
1611 io
.openx
.in
.timeout
= 0;
1612 io
.openx
.in
.fname
= fname
;
1614 io
.openx
.in
.open_func
= OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
;
1615 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1616 CHECK_STATUS(status
, NT_STATUS_OK
);
1617 smbcli_close(cli
->tree
, io
.openx
.out
.file
.fnum
);
1618 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1625 smbcli_close(cli
->tree
, fnum
);
1626 smbcli_unlink(cli
->tree
, fname
);
1627 smbcli_deltree(cli
->tree
, BASEDIR
);
1631 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1632 static bool test_stream_large_streaminfo(struct torture_context
*tctx
,
1633 struct smbcli_state
*cli
)
1635 #define LONG_STREAM_SIZE 2
1637 const char *fname
= BASEDIR
"\\stream.txt";
1638 const char *fname_stream
;
1642 union smb_fileinfo finfo
;
1644 if (!torture_setup_dir(cli
, BASEDIR
)) {
1648 lstream_name
= talloc_array(tctx
, char, LONG_STREAM_SIZE
);
1650 for (i
= 0; i
< LONG_STREAM_SIZE
- 1; i
++) {
1651 lstream_name
[i
] = (char)('a' + i
%26);
1653 lstream_name
[LONG_STREAM_SIZE
- 1] = '\0';
1655 torture_comment(tctx
, "(%s) Creating a file with a lot of streams\n", __location__
);
1656 for (i
= 0; i
< 10000; i
++) {
1657 fname_stream
= talloc_asprintf(tctx
, "%s:%s%d", fname
,
1659 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1665 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
1666 finfo
.generic
.in
.file
.path
= fname
;
1668 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1669 CHECK_STATUS(status
, STATUS_BUFFER_OVERFLOW
);
1672 smbcli_unlink(cli
->tree
, fname
);
1673 smbcli_deltree(cli
->tree
, BASEDIR
);
1677 /* Test the effect of setting attributes on a stream. */
1678 static bool test_stream_attributes(struct torture_context
*tctx
,
1679 struct smbcli_state
*cli
)
1684 const char *fname
= BASEDIR
"\\stream_attr.txt";
1685 const char *stream
= "Stream One:$DATA";
1686 const char *fname_stream
;
1688 union smb_fileinfo finfo
;
1689 union smb_setfileinfo sfinfo
;
1690 time_t basetime
= (time(NULL
) - 86400) & ~1;
1692 if (!torture_setup_dir(cli
, BASEDIR
)) {
1696 torture_comment(tctx
, "(%s) testing attribute setting on stream\n", __location__
);
1698 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1700 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1701 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1707 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1708 finfo
.generic
.in
.file
.path
= fname
;
1709 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1710 CHECK_STATUS(status
, NT_STATUS_OK
);
1712 if (finfo
.basic_info
.out
.attrib
!= FILE_ATTRIBUTE_ARCHIVE
) {
1713 printf("(%s) Incorrect attrib %x - should be %x\n", \
1714 __location__
, (unsigned int)finfo
.basic_info
.out
.attrib
,
1715 (unsigned int)FILE_ATTRIBUTE_ARCHIVE
);
1720 /* Now open the stream name. */
1722 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1723 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1724 io
.ntcreatex
.in
.flags
= 0;
1725 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1726 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
|SEC_FILE_WRITE_ATTRIBUTE
);
1727 io
.ntcreatex
.in
.create_options
= 0;
1728 io
.ntcreatex
.in
.file_attr
= 0;
1729 io
.ntcreatex
.in
.share_access
= 0;
1730 io
.ntcreatex
.in
.alloc_size
= 0;
1731 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1732 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1733 io
.ntcreatex
.in
.security_flags
= 0;
1734 io
.ntcreatex
.in
.fname
= fname_stream
;
1736 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1737 CHECK_STATUS(status
, NT_STATUS_OK
);
1739 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1741 /* Change the attributes + time on the stream fnum. */
1742 ZERO_STRUCT(sfinfo
);
1743 sfinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_READONLY
;
1744 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, basetime
);
1746 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1747 sfinfo
.generic
.in
.file
.fnum
= fnum
;
1748 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
1749 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1750 printf("(%s) %s - %s (should be %s)\n", __location__
, "SETATTR",
1751 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1756 smbcli_close(cli
->tree
, fnum
);
1760 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
1761 finfo
.generic
.in
.file
.path
= fname
;
1762 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1763 if (!NT_STATUS_IS_OK(status
)) {
1764 printf("(%s) %s pathinfo - %s\n", __location__
, "SETATTRE", nt_errstr(status
));
1769 if (finfo
.all_info
.out
.attrib
!= FILE_ATTRIBUTE_READONLY
) {
1770 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1772 (unsigned int)finfo
.all_info
.out
.attrib
,
1773 (unsigned int)FILE_ATTRIBUTE_READONLY
);
1778 if (nt_time_to_unix(finfo
.all_info
.out
.write_time
) != basetime
) {
1779 printf("(%s) time incorrect.\n",
1788 smbcli_close(cli
->tree
, fnum
);
1790 smbcli_unlink(cli
->tree
, fname
);
1791 smbcli_deltree(cli
->tree
, BASEDIR
);
1796 * A rough approximation of how a windows client creates the streams for use
1797 * in the summary tab.
1799 static bool test_stream_summary_tab(struct torture_context
*tctx
,
1800 struct smbcli_state
*cli
)
1805 const char *fname
= BASEDIR
"\\stream_summary.txt";
1806 const char *stream
= ":\005SummaryInformation:$DATA";
1807 const char *fname_stream
= NULL
;
1808 const char *tmp_stream
= ":Updt_\005SummaryInformation:$DATA";
1809 const char *fname_tmp_stream
= NULL
;
1811 union smb_fileinfo finfo
;
1812 union smb_rename rio
;
1815 if (!torture_setup_dir(cli
, BASEDIR
)) {
1819 fname_stream
= talloc_asprintf(tctx
, "%s%s", fname
, stream
);
1820 fname_tmp_stream
= talloc_asprintf(tctx
, "%s%s", fname
,
1823 /* Create summary info stream */
1824 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1829 /* Create summary info tmp update stream */
1830 ret
= create_file_with_stream(tctx
, cli
, fname_tmp_stream
);
1835 /* Open tmp stream and write to it */
1836 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1837 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1838 io
.ntcreatex
.in
.flags
= 0;
1839 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
1840 io
.ntcreatex
.in
.create_options
= 0;
1841 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1842 io
.ntcreatex
.in
.share_access
= 0;
1843 io
.ntcreatex
.in
.alloc_size
= 0;
1844 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1845 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1846 io
.ntcreatex
.in
.security_flags
= 0;
1847 io
.ntcreatex
.in
.fname
= fname_tmp_stream
;
1849 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1850 CHECK_STATUS(status
, NT_STATUS_OK
);
1851 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1853 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
1854 CHECK_VALUE(retsize
, 9);
1856 /* close the tmp stream. */
1857 smbcli_close(cli
->tree
, fnum
);
1860 /* Delete the current stream */
1861 smbcli_unlink(cli
->tree
, fname_stream
);
1863 /* Do the rename. */
1864 rio
.generic
.level
= RAW_RENAME_RENAME
;
1865 rio
.rename
.in
.pattern1
= fname_tmp_stream
;
1866 rio
.rename
.in
.pattern2
= stream
;
1867 rio
.rename
.in
.attrib
= FILE_ATTRIBUTE_SYSTEM
|
1868 FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
;
1869 status
= smb_raw_rename(cli
->tree
, &rio
);
1870 CHECK_STATUS(status
, NT_STATUS_OK
);
1872 /* Try to open the tmp stream that we just renamed away. */
1873 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1874 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1876 /* Query the base file to make sure it's still there. */
1877 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1878 finfo
.generic
.in
.file
.path
= fname
;
1880 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1881 CHECK_STATUS(status
, NT_STATUS_OK
);
1886 smbcli_close(cli
->tree
, fnum
);
1888 smbcli_unlink(cli
->tree
, fname
);
1890 smbcli_deltree(cli
->tree
, BASEDIR
);
1895 basic testing of streams calls
1897 struct torture_suite
*torture_raw_streams(TALLOC_CTX
*tctx
)
1899 struct torture_suite
*suite
= torture_suite_create(tctx
, "STREAMS");
1901 torture_suite_add_1smb_test(suite
, "DIR", test_stream_dir
);
1902 torture_suite_add_1smb_test(suite
, "IO", test_stream_io
);
1903 torture_suite_add_1smb_test(suite
, "SHAREMODES",
1904 test_stream_sharemodes
);
1905 torture_suite_add_1smb_test(suite
, "DELETE", test_stream_delete
);
1906 torture_suite_add_1smb_test(suite
, "NAMES", test_stream_names
);
1907 torture_suite_add_1smb_test(suite
, "NAMES2", test_stream_names2
);
1908 torture_suite_add_1smb_test(suite
, "RENAME", test_stream_rename
);
1909 torture_suite_add_1smb_test(suite
, "RENAME2", test_stream_rename2
);
1910 torture_suite_add_1smb_test(suite
, "RENAME3", test_stream_rename3
);
1911 torture_suite_add_1smb_test(suite
, "CREATEDISP",
1912 test_stream_create_disposition
);
1913 torture_suite_add_1smb_test(suite
, "ATTR", test_stream_attributes
);
1914 torture_suite_add_1smb_test(suite
, "SUMTAB", test_stream_summary_tab
);
1916 /* torture_suite_add_1smb_test(suite, "LARGESTREAMINFO", */
1917 /* test_stream_large_streaminfo); */