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"
30 #include "torture/raw/proto.h"
32 #define BASEDIR "\\teststreams"
34 #define CHECK_STATUS(status, correct) \
35 torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
37 #define CHECK_VALUE(v, correct) \
38 torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
40 #define CHECK_NTTIME(v, correct) \
41 torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
43 #define CHECK_STR(v, correct) do { \
45 if ((v) && !(correct)) { \
47 } else if (!(v) && (correct)) { \
49 } else if (!(v) && !(correct)) { \
51 } else if (strcmp((v), (correct)) == 0) { \
56 torture_assert(tctx,ok,\
57 talloc_asprintf(tctx, "got '%s', expected '%s'",\
58 (v)?(v):"NULL", (correct)?(correct):"NULL")); \
62 check that a stream has the right contents
64 static bool check_stream(struct smbcli_state
*cli
, const char *location
,
66 const char *fname
, const char *sname
,
70 const char *full_name
;
74 full_name
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, sname
);
76 fnum
= smbcli_open(cli
->tree
, full_name
, O_RDONLY
, DENY_NONE
);
80 printf("(%s) should have failed stream open of %s\n",
88 printf("(%s) Failed to open stream '%s' - %s\n",
89 location
, full_name
, smbcli_errstr(cli
->tree
));
93 buf
= talloc_array(mem_ctx
, uint8_t, strlen(value
)+11);
95 ret
= smbcli_read(cli
->tree
, fnum
, buf
, 0, strlen(value
)+11);
96 if (ret
!= strlen(value
)) {
97 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
98 location
, (long)strlen(value
), full_name
, (int)ret
);
102 if (memcmp(buf
, value
, strlen(value
)) != 0) {
103 printf("(%s) Bad data in stream\n", location
);
107 smbcli_close(cli
->tree
, fnum
);
111 static int qsort_string(char * const *s1
, char * const *s2
)
113 return strcmp(*s1
, *s2
);
116 static int qsort_stream(const struct stream_struct
*s1
, const struct stream_struct
*s2
)
118 return strcmp(s1
->stream_name
.s
, s2
->stream_name
.s
);
121 static bool check_stream_list(struct torture_context
*tctx
,
122 struct smbcli_state
*cli
, const char *fname
,
123 int num_exp
, const char **exp
)
125 union smb_fileinfo finfo
;
128 TALLOC_CTX
*tmp_ctx
= talloc_new(cli
);
130 struct stream_struct
*stream_sort
;
134 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
135 finfo
.generic
.in
.file
.path
= fname
;
137 status
= smb_raw_pathinfo(cli
->tree
, tmp_ctx
, &finfo
);
138 CHECK_STATUS(status
, NT_STATUS_OK
);
140 CHECK_VALUE(finfo
.stream_info
.out
.num_streams
, num_exp
);
147 exp_sort
= (char **)talloc_memdup(tmp_ctx
, exp
, num_exp
* sizeof(*exp
));
149 if (exp_sort
== NULL
) {
153 TYPESAFE_QSORT(exp_sort
, num_exp
, qsort_string
);
155 stream_sort
= (struct stream_struct
*)talloc_memdup(tmp_ctx
,
156 finfo
.stream_info
.out
.streams
,
157 finfo
.stream_info
.out
.num_streams
*
158 sizeof(*stream_sort
));
160 if (stream_sort
== NULL
) {
164 TYPESAFE_QSORT(stream_sort
, finfo
.stream_info
.out
.num_streams
, qsort_stream
);
166 for (i
=0; i
<num_exp
; i
++) {
167 if (strcmp(exp_sort
[i
], stream_sort
[i
].stream_name
.s
) != 0) {
175 talloc_free(tmp_ctx
);
179 for (i
=0; i
<num_exp
; i
++) {
180 torture_comment(tctx
, "stream names '%s' '%s'\n",
181 exp_sort
[i
], stream_sort
[i
].stream_name
.s
);
183 CHECK_STR(stream_sort
[fail
].stream_name
.s
, exp_sort
[fail
]);
184 talloc_free(tmp_ctx
);
189 test bahavior of streams on directories
191 static bool test_stream_dir(struct torture_context
*tctx
,
192 struct smbcli_state
*cli
)
196 const char *fname
= BASEDIR
"\\stream.txt";
199 const char *basedir_data
;
201 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
203 basedir_data
= talloc_asprintf(tctx
, "%s::$DATA", BASEDIR
);
204 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
206 printf("(%s) opening non-existent directory stream\n", __location__
);
207 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
208 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
209 io
.ntcreatex
.in
.flags
= 0;
210 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
211 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
212 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
213 io
.ntcreatex
.in
.share_access
= 0;
214 io
.ntcreatex
.in
.alloc_size
= 0;
215 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
216 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
217 io
.ntcreatex
.in
.security_flags
= 0;
218 io
.ntcreatex
.in
.fname
= sname1
;
219 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
220 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
222 printf("(%s) opening basedir stream\n", __location__
);
223 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
224 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
225 io
.ntcreatex
.in
.flags
= 0;
226 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
227 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
228 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_DIRECTORY
;
229 io
.ntcreatex
.in
.share_access
= 0;
230 io
.ntcreatex
.in
.alloc_size
= 0;
231 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
232 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
233 io
.ntcreatex
.in
.security_flags
= 0;
234 io
.ntcreatex
.in
.fname
= basedir_data
;
235 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
236 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
238 printf("(%s) opening basedir ::$DATA stream\n", __location__
);
239 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
240 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
241 io
.ntcreatex
.in
.flags
= 0x10;
242 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
243 io
.ntcreatex
.in
.create_options
= 0;
244 io
.ntcreatex
.in
.file_attr
= 0;
245 io
.ntcreatex
.in
.share_access
= 0;
246 io
.ntcreatex
.in
.alloc_size
= 0;
247 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
248 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
249 io
.ntcreatex
.in
.security_flags
= 0;
250 io
.ntcreatex
.in
.fname
= basedir_data
;
251 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
252 CHECK_STATUS(status
, NT_STATUS_FILE_IS_A_DIRECTORY
);
254 printf("(%s) list the streams on the basedir\n", __location__
);
255 ret
&= check_stream_list(tctx
, cli
, BASEDIR
, 0, NULL
);
257 smbcli_deltree(cli
->tree
, BASEDIR
);
262 test basic behavior of streams on directories
264 static bool test_stream_io(struct torture_context
*tctx
,
265 struct smbcli_state
*cli
)
269 const char *fname
= BASEDIR
"\\stream.txt";
270 const char *sname1
, *sname2
;
275 const char *one
[] = { "::$DATA" };
276 const char *two
[] = { "::$DATA", ":Second Stream:$DATA" };
277 const char *three
[] = { "::$DATA", ":Stream One:$DATA",
278 ":Second Stream:$DATA" };
280 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
282 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
283 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
285 printf("(%s) creating a stream on a non-existent file\n", __location__
);
286 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
287 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
288 io
.ntcreatex
.in
.flags
= 0;
289 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
290 io
.ntcreatex
.in
.create_options
= 0;
291 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
292 io
.ntcreatex
.in
.share_access
= 0;
293 io
.ntcreatex
.in
.alloc_size
= 0;
294 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
295 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
296 io
.ntcreatex
.in
.security_flags
= 0;
297 io
.ntcreatex
.in
.fname
= sname1
;
298 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
299 CHECK_STATUS(status
, NT_STATUS_OK
);
300 fnum
= io
.ntcreatex
.out
.file
.fnum
;
302 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", NULL
);
304 printf("(%s) check that open of base file is allowed\n", __location__
);
305 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
306 io
.ntcreatex
.in
.fname
= fname
;
307 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
308 CHECK_STATUS(status
, NT_STATUS_OK
);
309 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
311 printf("(%s) writing to stream\n", __location__
);
312 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
313 CHECK_VALUE(retsize
, 9);
315 smbcli_close(cli
->tree
, fnum
);
317 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test data");
319 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
320 io
.ntcreatex
.in
.fname
= sname1
;
321 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
322 CHECK_STATUS(status
, NT_STATUS_OK
);
323 fnum
= io
.ntcreatex
.out
.file
.fnum
;
325 printf("(%s) modifying stream\n", __location__
);
326 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "MORE DATA ", 5, 10);
327 CHECK_VALUE(retsize
, 10);
329 smbcli_close(cli
->tree
, fnum
);
331 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$FOO", NULL
);
333 printf("(%s) creating a stream2 on a existing file\n", __location__
);
334 io
.ntcreatex
.in
.fname
= sname2
;
335 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
336 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
337 CHECK_STATUS(status
, NT_STATUS_OK
);
338 fnum
= io
.ntcreatex
.out
.file
.fnum
;
340 printf("(%s) modifying stream\n", __location__
);
341 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "SECOND STREAM", 0, 13);
342 CHECK_VALUE(retsize
, 13);
344 smbcli_close(cli
->tree
, fnum
);
346 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test MORE DATA ");
347 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$DATA", "test MORE DATA ");
348 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:", NULL
);
349 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream", "SECOND STREAM");
350 ret
&= check_stream(cli
, __location__
, tctx
, fname
,
351 "SECOND STREAM:$DATA", "SECOND STREAM");
352 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$DATA", "SECOND STREAM");
353 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:", NULL
);
354 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$FOO", NULL
);
356 check_stream_list(tctx
, cli
, fname
, 3, three
);
358 printf("(%s) deleting stream\n", __location__
);
359 status
= smbcli_unlink(cli
->tree
, sname1
);
360 CHECK_STATUS(status
, NT_STATUS_OK
);
362 check_stream_list(tctx
, cli
, fname
, 2, two
);
364 printf("(%s) delete a stream via delete-on-close\n", __location__
);
365 io
.ntcreatex
.in
.fname
= sname2
;
366 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
367 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
368 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
369 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
371 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
372 CHECK_STATUS(status
, NT_STATUS_OK
);
373 fnum
= io
.ntcreatex
.out
.file
.fnum
;
375 smbcli_close(cli
->tree
, fnum
);
376 status
= smbcli_unlink(cli
->tree
, sname2
);
377 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
379 check_stream_list(tctx
, cli
, fname
, 1, one
);
381 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
382 io
.ntcreatex
.in
.fname
= sname1
;
383 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
384 CHECK_STATUS(status
, NT_STATUS_OK
);
385 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
386 io
.ntcreatex
.in
.fname
= sname2
;
387 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
388 CHECK_STATUS(status
, NT_STATUS_OK
);
389 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
391 printf("(%s) deleting file\n", __location__
);
392 status
= smbcli_unlink(cli
->tree
, fname
);
393 CHECK_STATUS(status
, NT_STATUS_OK
);
396 smbcli_close(cli
->tree
, fnum
);
397 smbcli_deltree(cli
->tree
, BASEDIR
);
402 test stream sharemodes
404 static bool test_stream_sharemodes(struct torture_context
*tctx
,
405 struct smbcli_state
*cli
)
409 const char *fname
= BASEDIR
"\\stream.txt";
410 const char *sname1
, *sname2
;
415 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
417 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
418 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
420 printf("(%s) testing stream share mode conflicts\n", __location__
);
421 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
422 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
423 io
.ntcreatex
.in
.flags
= 0;
424 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
425 io
.ntcreatex
.in
.create_options
= 0;
426 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
427 io
.ntcreatex
.in
.share_access
= 0;
428 io
.ntcreatex
.in
.alloc_size
= 0;
429 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
430 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
431 io
.ntcreatex
.in
.security_flags
= 0;
432 io
.ntcreatex
.in
.fname
= sname1
;
434 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
435 CHECK_STATUS(status
, NT_STATUS_OK
);
436 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
439 * A different stream does not give a sharing violation
442 io
.ntcreatex
.in
.fname
= sname2
;
443 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
444 CHECK_STATUS(status
, NT_STATUS_OK
);
445 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
448 * ... whereas the same stream does with unchanged access/share_access
452 io
.ntcreatex
.in
.fname
= sname1
;
453 io
.ntcreatex
.in
.open_disposition
= 0;
454 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
455 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
457 io
.ntcreatex
.in
.fname
= sname2
;
458 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
459 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
462 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
463 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
464 status
= smbcli_unlink(cli
->tree
, fname
);
465 smbcli_deltree(cli
->tree
, BASEDIR
);
470 * Test FILE_SHARE_DELETE on streams
472 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
473 * with SEC_STD_DELETE.
475 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
476 * be opened with SEC_STD_DELETE.
478 * A stream held open with FILE_SHARE_DELETE allows the file to be
479 * deleted. After the main file is deleted, access to the open file descriptor
480 * still works, but all name-based access to both the main file as well as the
481 * stream is denied with DELETE ending.
483 * This means, an open of the main file with SEC_STD_DELETE should walk all
484 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
485 * SHARING_VIOLATION, the main open fails.
487 * Closing the main file after delete_on_close has been set does not really
488 * unlink it but leaves the corresponding share mode entry with
489 * delete_on_close being set around until all streams are closed.
491 * Opening a stream must also look at the main file's share mode entry, look
492 * at the delete_on_close bit and potentially return DELETE_PENDING.
495 static bool test_stream_delete(struct torture_context
*tctx
,
496 struct smbcli_state
*cli
)
500 const char *fname
= BASEDIR
"\\stream.txt";
506 union smb_fileinfo finfo
;
508 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
510 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
512 printf("(%s) opening non-existent file stream\n", __location__
);
513 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
514 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
515 io
.ntcreatex
.in
.flags
= 0;
516 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
517 io
.ntcreatex
.in
.create_options
= 0;
518 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
519 io
.ntcreatex
.in
.share_access
= 0;
520 io
.ntcreatex
.in
.alloc_size
= 0;
521 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
522 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
523 io
.ntcreatex
.in
.security_flags
= 0;
524 io
.ntcreatex
.in
.fname
= sname1
;
526 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
527 CHECK_STATUS(status
, NT_STATUS_OK
);
528 fnum
= io
.ntcreatex
.out
.file
.fnum
;
530 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
531 CHECK_VALUE(retsize
, 9);
534 * One stream opened without FILE_SHARE_DELETE prevents the main file
535 * to be deleted or even opened with DELETE access
538 status
= smbcli_unlink(cli
->tree
, fname
);
539 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
541 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
542 io
.ntcreatex
.in
.fname
= fname
;
543 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
544 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
545 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
547 smbcli_close(cli
->tree
, fnum
);
550 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
553 io
.ntcreatex
.in
.fname
= sname1
;
554 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
555 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
556 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
557 CHECK_STATUS(status
, NT_STATUS_OK
);
558 fnum
= io
.ntcreatex
.out
.file
.fnum
;
560 status
= smbcli_unlink(cli
->tree
, fname
);
561 CHECK_STATUS(status
, NT_STATUS_OK
);
564 * file access still works on the stream while the main file is closed
567 retsize
= smbcli_read(cli
->tree
, fnum
, buf
, 0, 9);
568 CHECK_VALUE(retsize
, 9);
570 finfo
.generic
.level
= RAW_FILEINFO_STANDARD
;
571 finfo
.generic
.in
.file
.path
= fname
;
574 * name-based access to both the main file and the stream does not
575 * work anymore but gives DELETE_PENDING
578 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
579 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
582 * older S3 doesn't do this
584 finfo
.generic
.in
.file
.path
= sname1
;
585 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
586 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
589 * fd-based qfileinfo on the stream still works, the stream does not
590 * have the delete-on-close bit set. This could mean that open on the
591 * stream first opens the main file
594 finfo
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
595 finfo
.all_info
.in
.file
.fnum
= fnum
;
597 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo
);
598 CHECK_STATUS(status
, NT_STATUS_OK
);
600 /* w2k and w2k3 return 0 and w2k8 returns 1 */
601 if (TARGET_IS_WINXP(tctx
) || TARGET_IS_W2K3(tctx
) ||
602 TARGET_IS_SAMBA3(tctx
)) {
603 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 0);
605 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 1);
608 smbcli_close(cli
->tree
, fnum
);
611 * After closing the stream the file is really gone.
614 finfo
.generic
.in
.file
.path
= fname
;
615 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
616 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
618 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
620 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
621 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
622 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
623 CHECK_STATUS(status
, NT_STATUS_OK
);
624 fnum
= io
.ntcreatex
.out
.file
.fnum
;
626 finfo
.generic
.in
.file
.path
= fname
;
627 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
628 CHECK_STATUS(status
, NT_STATUS_OK
);
630 smbcli_close(cli
->tree
, fnum
);
632 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
633 CHECK_STATUS(status
, NT_STATUS_OK
);
635 smbcli_close(cli
->tree
, fnum
);
636 smbcli_unlink(cli
->tree
, fname
);
637 smbcli_deltree(cli
->tree
, BASEDIR
);
644 static bool test_stream_names(struct torture_context
*tctx
,
645 struct smbcli_state
*cli
)
649 union smb_fileinfo finfo
;
650 union smb_fileinfo stinfo
;
651 union smb_setfileinfo sinfo
;
652 const char *fname
= BASEDIR
"\\stream_names.txt";
653 const char *sname1
, *sname1b
, *sname1c
, *sname1d
;
654 const char *sname2
, *snamew
, *snamew2
;
655 const char *snamer1
, *snamer2
;
661 const char *four
[4] = {
663 ":\x05Stream\n One:$DATA",
664 ":MStream Two:$DATA",
667 const char *five1
[5] = {
669 ":\x05Stream\n One:$DATA",
670 ":BeforeRename:$DATA",
671 ":MStream Two:$DATA",
674 const char *five2
[5] = {
676 ":\x05Stream\n One:$DATA",
677 ":AfterRename:$DATA",
678 ":MStream Two:$DATA",
682 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
684 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "\x05Stream\n One");
685 sname1b
= talloc_asprintf(tctx
, "%s:", sname1
);
686 sname1c
= talloc_asprintf(tctx
, "%s:$FOO", sname1
);
687 sname1d
= talloc_asprintf(tctx
, "%s:?D*a", sname1
);
688 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "MStream Two");
689 snamew
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "?Stream*");
690 snamew2
= talloc_asprintf(tctx
, "%s\\stream*:%s:$DATA", BASEDIR
, "?Stream*");
691 snamer1
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "BeforeRename");
692 snamer2
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "AfterRename");
694 printf("(%s) testing stream names\n", __location__
);
695 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
696 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
697 io
.ntcreatex
.in
.flags
= 0;
698 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
699 io
.ntcreatex
.in
.create_options
= 0;
700 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
701 io
.ntcreatex
.in
.share_access
= 0;
702 io
.ntcreatex
.in
.alloc_size
= 0;
703 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
704 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
705 io
.ntcreatex
.in
.security_flags
= 0;
706 io
.ntcreatex
.in
.fname
= fname
;
708 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
709 CHECK_STATUS(status
, NT_STATUS_OK
);
710 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
713 * Make sure the create time of the streams are different from the
717 smbcli_close(cli
->tree
, fnum1
);
719 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
720 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
721 io
.ntcreatex
.in
.flags
= 0;
722 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
723 io
.ntcreatex
.in
.create_options
= 0;
724 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
725 io
.ntcreatex
.in
.share_access
= 0;
726 io
.ntcreatex
.in
.alloc_size
= 0;
727 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
728 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
729 io
.ntcreatex
.in
.security_flags
= 0;
730 io
.ntcreatex
.in
.fname
= sname1
;
732 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
733 CHECK_STATUS(status
, NT_STATUS_OK
);
734 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
737 * A different stream does not give a sharing violation
740 io
.ntcreatex
.in
.fname
= sname2
;
741 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
742 CHECK_STATUS(status
, NT_STATUS_OK
);
743 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
746 * ... whereas the same stream does with unchanged access/share_access
750 io
.ntcreatex
.in
.fname
= sname1
;
751 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
752 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
753 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
755 io
.ntcreatex
.in
.fname
= sname1b
;
756 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
757 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
759 io
.ntcreatex
.in
.fname
= sname1c
;
760 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
761 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
762 /* w2k returns INVALID_PARAMETER */
763 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
765 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
768 io
.ntcreatex
.in
.fname
= sname1d
;
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
= sname2
;
778 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
779 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
781 io
.ntcreatex
.in
.fname
= snamew
;
782 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
783 CHECK_STATUS(status
, NT_STATUS_OK
);
784 fnum3
= io
.ntcreatex
.out
.file
.fnum
;
786 io
.ntcreatex
.in
.fname
= snamew2
;
787 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
788 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
790 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
792 smbcli_close(cli
->tree
, fnum1
);
793 smbcli_close(cli
->tree
, fnum2
);
794 smbcli_close(cli
->tree
, fnum3
);
796 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
797 finfo
.generic
.in
.file
.path
= fname
;
798 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
799 CHECK_STATUS(status
, NT_STATUS_OK
);
801 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
803 for (i
=0; i
< 4; i
++) {
805 uint64_t stream_size
;
806 char *path
= talloc_asprintf(tctx
, "%s%s",
809 char *rpath
= talloc_strdup(path
, path
);
810 char *p
= strrchr(rpath
, ':');
818 printf("(%s): i[%u][%s]\n", __location__
, i
, path
);
819 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
820 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
821 SEC_FILE_WRITE_ATTRIBUTE
|
823 io
.ntcreatex
.in
.fname
= path
;
824 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
825 CHECK_STATUS(status
, NT_STATUS_OK
);
826 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
828 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
829 finfo
.generic
.in
.file
.path
= fname
;
830 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
831 CHECK_STATUS(status
, NT_STATUS_OK
);
833 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
834 stinfo
.generic
.in
.file
.fnum
= fnum1
;
835 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
836 CHECK_STATUS(status
, NT_STATUS_OK
);
837 if (!torture_setting_bool(tctx
, "samba3", false)) {
838 CHECK_NTTIME(stinfo
.all_info
.out
.create_time
,
839 finfo
.all_info
.out
.create_time
);
840 CHECK_NTTIME(stinfo
.all_info
.out
.access_time
,
841 finfo
.all_info
.out
.access_time
);
842 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
843 finfo
.all_info
.out
.write_time
);
844 CHECK_NTTIME(stinfo
.all_info
.out
.change_time
,
845 finfo
.all_info
.out
.change_time
);
847 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
848 finfo
.all_info
.out
.attrib
);
849 CHECK_VALUE(stinfo
.all_info
.out
.size
,
850 finfo
.all_info
.out
.size
);
851 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
852 finfo
.all_info
.out
.delete_pending
);
853 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
854 finfo
.all_info
.out
.directory
);
855 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
856 finfo
.all_info
.out
.ea_size
);
858 stinfo
.generic
.level
= RAW_FILEINFO_NAME_INFO
;
859 stinfo
.generic
.in
.file
.fnum
= fnum1
;
860 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
861 CHECK_STATUS(status
, NT_STATUS_OK
);
862 if (!torture_setting_bool(tctx
, "samba3", false)) {
863 CHECK_STR(stinfo
.name_info
.out
.fname
.s
, rpath
);
866 write_time
= finfo
.all_info
.out
.write_time
;
867 write_time
+= i
*1000000;
868 write_time
/= 1000000;
869 write_time
*= 1000000;
872 sinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
873 sinfo
.basic_info
.in
.file
.fnum
= fnum1
;
874 sinfo
.basic_info
.in
.write_time
= write_time
;
875 sinfo
.basic_info
.in
.attrib
= stinfo
.all_info
.out
.attrib
;
876 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
877 CHECK_STATUS(status
, NT_STATUS_OK
);
879 stream_size
= i
*8192;
882 sinfo
.end_of_file_info
.level
= RAW_SFILEINFO_END_OF_FILE_INFO
;
883 sinfo
.end_of_file_info
.in
.file
.fnum
= fnum1
;
884 sinfo
.end_of_file_info
.in
.size
= stream_size
;
885 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
886 CHECK_STATUS(status
, NT_STATUS_OK
);
888 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
889 stinfo
.generic
.in
.file
.fnum
= fnum1
;
890 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
891 CHECK_STATUS(status
, NT_STATUS_OK
);
892 if (!torture_setting_bool(tctx
, "samba3", false)) {
893 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
895 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
896 finfo
.all_info
.out
.attrib
);
898 CHECK_VALUE(stinfo
.all_info
.out
.size
,
900 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
901 finfo
.all_info
.out
.delete_pending
);
902 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
903 finfo
.all_info
.out
.directory
);
904 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
905 finfo
.all_info
.out
.ea_size
);
907 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
909 smbcli_close(cli
->tree
, fnum1
);
913 printf("(%s): testing stream renames\n", __location__
);
914 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
915 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
916 SEC_FILE_WRITE_ATTRIBUTE
|
918 io
.ntcreatex
.in
.fname
= snamer1
;
919 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
920 CHECK_STATUS(status
, NT_STATUS_OK
);
921 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
923 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five1
);
926 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
927 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
928 sinfo
.rename_information
.in
.overwrite
= true;
929 sinfo
.rename_information
.in
.root_fid
= 0;
930 sinfo
.rename_information
.in
.new_name
= ":AfterRename:$DATA";
931 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
932 CHECK_STATUS(status
, NT_STATUS_OK
);
934 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
937 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
938 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
939 sinfo
.rename_information
.in
.overwrite
= false;
940 sinfo
.rename_information
.in
.root_fid
= 0;
941 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
942 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
943 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
945 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
948 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
949 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
950 sinfo
.rename_information
.in
.overwrite
= true;
951 sinfo
.rename_information
.in
.root_fid
= 0;
952 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
953 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
954 if (torture_setting_bool(tctx
, "samba4", false) ||
955 torture_setting_bool(tctx
, "samba3", false)) {
956 /* why should this rename be considered invalid?? */
957 CHECK_STATUS(status
, NT_STATUS_OK
);
958 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
960 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
961 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
965 /* TODO: we need to test more rename combinations */
968 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
969 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
970 if (fnum3
!= -1) smbcli_close(cli
->tree
, fnum3
);
971 status
= smbcli_unlink(cli
->tree
, fname
);
972 smbcli_deltree(cli
->tree
, BASEDIR
);
979 static bool test_stream_names2(struct torture_context
*tctx
,
980 struct smbcli_state
*cli
)
984 const char *fname
= BASEDIR
"\\stream_names2.txt";
989 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
991 printf("(%s) testing stream names\n", __location__
);
992 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
993 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
994 io
.ntcreatex
.in
.flags
= 0;
995 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
996 io
.ntcreatex
.in
.create_options
= 0;
997 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
998 io
.ntcreatex
.in
.share_access
= 0;
999 io
.ntcreatex
.in
.alloc_size
= 0;
1000 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1001 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1002 io
.ntcreatex
.in
.security_flags
= 0;
1003 io
.ntcreatex
.in
.fname
= fname
;
1004 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1005 CHECK_STATUS(status
, NT_STATUS_OK
);
1006 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
1008 for (i
=0x01; i
< 0x7F; i
++) {
1009 char *path
= talloc_asprintf(tctx
, "%s:Stream%c0x%02X:$DATA",
1017 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1020 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1025 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1026 io
.ntcreatex
.in
.fname
= path
;
1027 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1028 if (!NT_STATUS_EQUAL(status
, expected
)) {
1029 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1030 __location__
, fname
, isprint(i
)?(char)i
:' ', i
,
1031 isprint(i
)?"":" (not printable)",
1032 nt_errstr(expected
));
1034 CHECK_STATUS(status
, expected
);
1040 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
1041 status
= smbcli_unlink(cli
->tree
, fname
);
1042 smbcli_deltree(cli
->tree
, BASEDIR
);
1046 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1047 check_fnum = true; \
1048 call_name = #call; \
1049 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1050 sfinfo.generic.in.file.fnum = fnum; \
1051 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1052 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1053 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1054 nt_errstr(status), nt_errstr(rightstatus)); \
1057 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1058 finfo1.generic.in.file.fnum = fnum; \
1059 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1060 if (!NT_STATUS_IS_OK(status2)) { \
1061 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1068 static bool test_stream_rename(struct torture_context
*tctx
,
1069 struct smbcli_state
*cli
)
1071 NTSTATUS status
, status2
;
1073 const char *fname
= BASEDIR
"\\stream_rename.txt";
1074 const char *sname1
, *sname2
;
1075 union smb_fileinfo finfo1
;
1076 union smb_setfileinfo sfinfo
;
1080 const char *call_name
;
1082 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1084 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
1085 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1087 printf("(%s) testing stream renames\n", __location__
);
1088 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1089 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1090 io
.ntcreatex
.in
.flags
= 0;
1091 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1092 SEC_FILE_WRITE_ATTRIBUTE
|
1093 SEC_RIGHTS_FILE_ALL
;
1094 io
.ntcreatex
.in
.create_options
= 0;
1095 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1096 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1097 io
.ntcreatex
.in
.alloc_size
= 0;
1098 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1099 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1100 io
.ntcreatex
.in
.security_flags
= 0;
1101 io
.ntcreatex
.in
.fname
= sname1
;
1103 /* Create two streams. */
1104 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1105 CHECK_STATUS(status
, NT_STATUS_OK
);
1106 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1107 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1109 io
.ntcreatex
.in
.fname
= sname2
;
1110 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1111 CHECK_STATUS(status
, NT_STATUS_OK
);
1112 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1114 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1117 * Open the second stream.
1120 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1121 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1122 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1123 CHECK_STATUS(status
, NT_STATUS_OK
);
1124 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1127 * Now rename the second stream onto the first.
1130 ZERO_STRUCT(sfinfo
);
1132 sfinfo
.rename_information
.in
.overwrite
= 1;
1133 sfinfo
.rename_information
.in
.root_fid
= 0;
1134 sfinfo
.rename_information
.in
.new_name
= ":Stream One";
1135 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1138 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1139 status
= smbcli_unlink(cli
->tree
, fname
);
1140 smbcli_deltree(cli
->tree
, BASEDIR
);
1144 static bool test_stream_rename2(struct torture_context
*tctx
,
1145 struct smbcli_state
*cli
)
1149 const char *fname1
= BASEDIR
"\\stream.txt";
1150 const char *fname2
= BASEDIR
"\\stream2.txt";
1151 const char *stream_name1
= ":Stream One:$DATA";
1152 const char *stream_name2
= ":Stream Two:$DATA";
1153 const char *stream_name_default
= "::$DATA";
1158 union smb_setfileinfo sinfo
;
1159 union smb_rename rio
;
1161 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1163 sname1
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream One");
1164 sname2
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream Two");
1166 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1167 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1168 io
.ntcreatex
.in
.flags
= 0;
1169 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1170 SEC_STD_DELETE
|SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1171 io
.ntcreatex
.in
.create_options
= 0;
1172 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1173 io
.ntcreatex
.in
.share_access
= (NTCREATEX_SHARE_ACCESS_READ
|
1174 NTCREATEX_SHARE_ACCESS_WRITE
|
1175 NTCREATEX_SHARE_ACCESS_DELETE
);
1176 io
.ntcreatex
.in
.alloc_size
= 0;
1177 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1178 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1179 io
.ntcreatex
.in
.security_flags
= 0;
1180 io
.ntcreatex
.in
.fname
= sname1
;
1182 /* Open/create new stream. */
1183 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1184 CHECK_STATUS(status
, NT_STATUS_OK
);
1186 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1189 * Check raw rename with <base>:<stream>.
1191 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1193 rio
.generic
.level
= RAW_RENAME_NTRENAME
;
1194 rio
.ntrename
.in
.old_name
= sname1
;
1195 rio
.ntrename
.in
.new_name
= sname2
;
1196 rio
.ntrename
.in
.attrib
= 0;
1197 rio
.ntrename
.in
.cluster_size
= 0;
1198 rio
.ntrename
.in
.flags
= RENAME_FLAG_RENAME
;
1199 status
= smb_raw_rename(cli
->tree
, &rio
);
1200 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1203 * Check raw rename to the default stream using :<stream>.
1205 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1207 rio
.ntrename
.in
.new_name
= stream_name_default
;
1208 status
= smb_raw_rename(cli
->tree
, &rio
);
1209 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
1212 * Check raw rename using :<stream>.
1214 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1216 rio
.ntrename
.in
.new_name
= stream_name2
;
1217 status
= smb_raw_rename(cli
->tree
, &rio
);
1218 CHECK_STATUS(status
, NT_STATUS_OK
);
1221 * Check raw rename of a stream to a file.
1223 printf("(%s) Checking NTRENAME of a stream to a file\n",
1225 rio
.ntrename
.in
.old_name
= sname2
;
1226 rio
.ntrename
.in
.new_name
= fname2
;
1227 status
= smb_raw_rename(cli
->tree
, &rio
);
1228 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1231 * Check raw rename of a file to a stream.
1233 printf("(%s) Checking NTRENAME of a file to a stream\n",
1236 /* Create the file. */
1237 io
.ntcreatex
.in
.fname
= fname2
;
1238 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1239 CHECK_STATUS(status
, NT_STATUS_OK
);
1240 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1242 /* Try the rename. */
1243 rio
.ntrename
.in
.old_name
= fname2
;
1244 rio
.ntrename
.in
.new_name
= sname1
;
1245 status
= smb_raw_rename(cli
->tree
, &rio
);
1246 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
1249 * Reopen the stream for trans2 renames.
1251 io
.ntcreatex
.in
.fname
= sname2
;
1252 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1253 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1254 CHECK_STATUS(status
, NT_STATUS_OK
);
1255 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1258 * Check trans2 rename of a stream using :<stream>.
1260 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1263 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1264 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1265 sinfo
.rename_information
.in
.overwrite
= 1;
1266 sinfo
.rename_information
.in
.root_fid
= 0;
1267 sinfo
.rename_information
.in
.new_name
= stream_name1
;
1268 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1269 CHECK_STATUS(status
, NT_STATUS_OK
);
1272 * Check trans2 rename of an overwriting stream using :<stream>.
1274 printf("(%s) Checking trans2 rename of an overwriting stream using "
1275 ":<stream>\n", __location__
);
1277 /* Create second stream. */
1278 io
.ntcreatex
.in
.fname
= sname2
;
1279 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1280 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1281 CHECK_STATUS(status
, NT_STATUS_OK
);
1282 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1284 /* Rename the first stream onto the second. */
1285 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1286 sinfo
.rename_information
.in
.new_name
= stream_name2
;
1287 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1288 CHECK_STATUS(status
, NT_STATUS_OK
);
1290 smbcli_close(cli
->tree
, fnum
);
1293 * Reopen the stream with the new name.
1295 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1296 io
.ntcreatex
.in
.fname
= sname2
;
1297 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1298 CHECK_STATUS(status
, NT_STATUS_OK
);
1299 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1302 * Check trans2 rename of a stream using <base>:<stream>.
1304 printf("(%s) Checking trans2 rename of a stream using "
1305 "<base>:<stream>\n", __location__
);
1306 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1307 sinfo
.rename_information
.in
.new_name
= sname1
;
1308 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1309 CHECK_STATUS(status
, NT_STATUS_NOT_SUPPORTED
);
1312 * Samba3 doesn't currently support renaming a stream to the default
1313 * stream. This test does pass on windows.
1315 if (torture_setting_bool(tctx
, "samba3", false) ||
1316 torture_setting_bool(tctx
, "samba4", false)) {
1321 * Check trans2 rename to the default stream using :<stream>.
1323 printf("(%s) Checking trans2 rename to defaualt stream using "
1324 ":<stream>\n", __location__
);
1325 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1326 sinfo
.rename_information
.in
.new_name
= stream_name_default
;
1327 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1328 CHECK_STATUS(status
, NT_STATUS_OK
);
1330 smbcli_close(cli
->tree
, fnum
);
1333 smbcli_close(cli
->tree
, fnum
);
1334 status
= smbcli_unlink(cli
->tree
, fname1
);
1335 status
= smbcli_unlink(cli
->tree
, fname2
);
1336 smbcli_deltree(cli
->tree
, BASEDIR
);
1343 static bool test_stream_rename3(struct torture_context
*tctx
,
1344 struct smbcli_state
*cli
)
1346 NTSTATUS status
, status2
;
1348 const char *fname
= BASEDIR
"\\stream_rename.txt";
1349 const char *sname1
, *sname2
;
1350 union smb_fileinfo finfo1
;
1351 union smb_setfileinfo sfinfo
;
1356 const char *call_name
;
1358 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1360 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "MStream Two:$DATA");
1361 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1363 printf("(%s) testing stream renames\n", __location__
);
1364 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1365 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1366 io
.ntcreatex
.in
.flags
= 0;
1367 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1368 SEC_FILE_WRITE_ATTRIBUTE
|
1369 SEC_RIGHTS_FILE_ALL
;
1370 io
.ntcreatex
.in
.create_options
= 0;
1371 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1372 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1373 NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1374 io
.ntcreatex
.in
.alloc_size
= 0;
1375 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1376 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1377 io
.ntcreatex
.in
.security_flags
= 0;
1378 io
.ntcreatex
.in
.fname
= sname1
;
1380 /* Create two streams. */
1381 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1382 CHECK_STATUS(status
, NT_STATUS_OK
);
1383 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1384 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1386 io
.ntcreatex
.in
.fname
= sname2
;
1387 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1388 CHECK_STATUS(status
, NT_STATUS_OK
);
1389 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1391 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1393 /* open the second stream. */
1394 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1395 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1396 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1397 CHECK_STATUS(status
, NT_STATUS_OK
);
1398 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1400 /* Keep a handle to the first stream open. */
1401 io
.ntcreatex
.in
.fname
= sname1
;
1402 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1403 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1404 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1405 CHECK_STATUS(status
, NT_STATUS_OK
);
1406 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
1408 ZERO_STRUCT(sfinfo
);
1409 sfinfo
.rename_information
.in
.overwrite
= 1;
1410 sfinfo
.rename_information
.in
.root_fid
= 0;
1411 sfinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1412 if (torture_setting_bool(tctx
, "samba4", false) ||
1413 torture_setting_bool(tctx
, "samba3", false)) {
1414 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1416 CHECK_CALL_FNUM(RENAME_INFORMATION
,
1417 NT_STATUS_INVALID_PARAMETER
);
1422 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1423 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
1424 status
= smbcli_unlink(cli
->tree
, fname
);
1425 smbcli_deltree(cli
->tree
, BASEDIR
);
1429 static bool create_file_with_stream(struct torture_context
*tctx
,
1430 struct smbcli_state
*cli
,
1437 /* Create a file with a stream */
1438 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1439 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1440 io
.ntcreatex
.in
.flags
= 0;
1441 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1442 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1443 io
.ntcreatex
.in
.create_options
= 0;
1444 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1445 io
.ntcreatex
.in
.share_access
= 0;
1446 io
.ntcreatex
.in
.alloc_size
= 0;
1447 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1448 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1449 io
.ntcreatex
.in
.security_flags
= 0;
1450 io
.ntcreatex
.in
.fname
= stream
;
1452 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1453 CHECK_STATUS(status
, NT_STATUS_OK
);
1456 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1460 /* Test how streams interact with create dispositions */
1461 static bool test_stream_create_disposition(struct torture_context
*tctx
,
1462 struct smbcli_state
*cli
)
1466 const char *fname
= BASEDIR
"\\stream.txt";
1467 const char *stream
= "Stream One:$DATA";
1468 const char *fname_stream
;
1469 const char *default_stream_name
= "::$DATA";
1470 const char *stream_list
[2];
1474 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1476 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1478 stream_list
[0] = talloc_asprintf(tctx
, ":%s", stream
);
1479 stream_list
[1] = default_stream_name
;
1481 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1485 /* Open the base file with OPEN */
1486 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1487 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1488 io
.ntcreatex
.in
.flags
= 0;
1489 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1490 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1491 io
.ntcreatex
.in
.create_options
= 0;
1492 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1493 io
.ntcreatex
.in
.share_access
= 0;
1494 io
.ntcreatex
.in
.alloc_size
= 0;
1495 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1496 io
.ntcreatex
.in
.security_flags
= 0;
1497 io
.ntcreatex
.in
.fname
= fname
;
1500 * check ntcreatex open: sanity check
1502 printf("(%s) Checking ntcreatex disp: open\n", __location__
);
1503 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1504 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1505 CHECK_STATUS(status
, NT_STATUS_OK
);
1506 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1507 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1512 * check ntcreatex overwrite
1514 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__
);
1515 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
1516 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1517 CHECK_STATUS(status
, NT_STATUS_OK
);
1518 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1519 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1524 * check ntcreatex overwrite_if
1526 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__
);
1527 smbcli_unlink(cli
->tree
, fname
);
1528 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1532 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1533 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1534 CHECK_STATUS(status
, NT_STATUS_OK
);
1535 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1536 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1541 * check ntcreatex supersede
1543 printf("(%s) Checking ntcreatex disp: supersede\n", __location__
);
1544 smbcli_unlink(cli
->tree
, fname
);
1545 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1549 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
1550 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1551 CHECK_STATUS(status
, NT_STATUS_OK
);
1552 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1553 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1558 * check ntcreatex overwrite_if on a stream.
1560 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1562 smbcli_unlink(cli
->tree
, fname
);
1563 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1567 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1568 io
.ntcreatex
.in
.fname
= fname_stream
;
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
, 2, stream_list
)) {
1577 * check openx overwrite_if
1579 printf("(%s) Checking openx disp: overwrite_if\n", __location__
);
1580 smbcli_unlink(cli
->tree
, fname
);
1581 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1585 io
.openx
.level
= RAW_OPEN_OPENX
;
1586 io
.openx
.in
.flags
= OPENX_FLAGS_ADDITIONAL_INFO
;
1587 io
.openx
.in
.open_mode
= OPENX_MODE_ACCESS_RDWR
| OPEN_FLAGS_DENY_NONE
;
1588 io
.openx
.in
.search_attrs
= 0;
1589 io
.openx
.in
.file_attrs
= 0;
1590 io
.openx
.in
.write_time
= 0;
1591 io
.openx
.in
.size
= 1024*1024;
1592 io
.openx
.in
.timeout
= 0;
1593 io
.openx
.in
.fname
= fname
;
1595 io
.openx
.in
.open_func
= OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
;
1596 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1597 CHECK_STATUS(status
, NT_STATUS_OK
);
1598 smbcli_close(cli
->tree
, io
.openx
.out
.file
.fnum
);
1599 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1606 smbcli_close(cli
->tree
, fnum
);
1607 smbcli_unlink(cli
->tree
, fname
);
1608 smbcli_deltree(cli
->tree
, BASEDIR
);
1613 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1614 static bool test_stream_large_streaminfo(struct torture_context
*tctx
,
1615 struct smbcli_state
*cli
)
1617 #define LONG_STREAM_SIZE 2
1619 const char *fname
= BASEDIR
"\\stream.txt";
1620 const char *fname_stream
;
1624 union smb_fileinfo finfo
;
1626 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1628 lstream_name
= talloc_array(tctx
, char, LONG_STREAM_SIZE
);
1630 for (i
= 0; i
< LONG_STREAM_SIZE
- 1; i
++) {
1631 lstream_name
[i
] = (char)('a' + i
%26);
1633 lstream_name
[LONG_STREAM_SIZE
- 1] = '\0';
1635 torture_comment(tctx
, "(%s) Creating a file with a lot of streams\n", __location__
);
1636 for (i
= 0; i
< 10000; i
++) {
1637 fname_stream
= talloc_asprintf(tctx
, "%s:%s%d", fname
,
1639 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1645 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
1646 finfo
.generic
.in
.file
.path
= fname
;
1648 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1649 CHECK_STATUS(status
, STATUS_BUFFER_OVERFLOW
);
1652 smbcli_unlink(cli
->tree
, fname
);
1653 smbcli_deltree(cli
->tree
, BASEDIR
);
1658 /* Test the effect of setting attributes on a stream. */
1659 static bool test_stream_attributes(struct torture_context
*tctx
,
1660 struct smbcli_state
*cli
)
1665 const char *fname
= BASEDIR
"\\stream_attr.txt";
1666 const char *stream
= "Stream One:$DATA";
1667 const char *fname_stream
;
1669 union smb_fileinfo finfo
;
1670 union smb_setfileinfo sfinfo
;
1671 time_t basetime
= (time(NULL
) - 86400) & ~1;
1673 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1675 torture_comment(tctx
, "(%s) testing attribute setting on stream\n", __location__
);
1677 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1679 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1680 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1686 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1687 finfo
.generic
.in
.file
.path
= fname
;
1688 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1689 CHECK_STATUS(status
, NT_STATUS_OK
);
1691 if (finfo
.basic_info
.out
.attrib
!= FILE_ATTRIBUTE_ARCHIVE
) {
1692 printf("(%s) Incorrect attrib %x - should be %x\n", \
1693 __location__
, (unsigned int)finfo
.basic_info
.out
.attrib
,
1694 (unsigned int)FILE_ATTRIBUTE_ARCHIVE
);
1699 /* Now open the stream name. */
1701 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1702 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1703 io
.ntcreatex
.in
.flags
= 0;
1704 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1705 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
|SEC_FILE_WRITE_ATTRIBUTE
);
1706 io
.ntcreatex
.in
.create_options
= 0;
1707 io
.ntcreatex
.in
.file_attr
= 0;
1708 io
.ntcreatex
.in
.share_access
= 0;
1709 io
.ntcreatex
.in
.alloc_size
= 0;
1710 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1711 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1712 io
.ntcreatex
.in
.security_flags
= 0;
1713 io
.ntcreatex
.in
.fname
= fname_stream
;
1715 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1716 CHECK_STATUS(status
, NT_STATUS_OK
);
1718 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1720 /* Change the attributes + time on the stream fnum. */
1721 ZERO_STRUCT(sfinfo
);
1722 sfinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_READONLY
;
1723 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, basetime
);
1725 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1726 sfinfo
.generic
.in
.file
.fnum
= fnum
;
1727 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
1728 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1729 printf("(%s) %s - %s (should be %s)\n", __location__
, "SETATTR",
1730 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1735 smbcli_close(cli
->tree
, fnum
);
1739 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
1740 finfo
.generic
.in
.file
.path
= fname
;
1741 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1742 if (!NT_STATUS_IS_OK(status
)) {
1743 printf("(%s) %s pathinfo - %s\n", __location__
, "SETATTRE", nt_errstr(status
));
1748 if (finfo
.all_info
.out
.attrib
!= FILE_ATTRIBUTE_READONLY
) {
1749 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1751 (unsigned int)finfo
.all_info
.out
.attrib
,
1752 (unsigned int)FILE_ATTRIBUTE_READONLY
);
1757 if (nt_time_to_unix(finfo
.all_info
.out
.write_time
) != basetime
) {
1758 printf("(%s) time incorrect.\n",
1767 smbcli_close(cli
->tree
, fnum
);
1769 smbcli_unlink(cli
->tree
, fname
);
1770 smbcli_deltree(cli
->tree
, BASEDIR
);
1775 * A rough approximation of how a windows client creates the streams for use
1776 * in the summary tab.
1778 static bool test_stream_summary_tab(struct torture_context
*tctx
,
1779 struct smbcli_state
*cli
)
1784 const char *fname
= BASEDIR
"\\stream_summary.txt";
1785 const char *stream
= ":\005SummaryInformation:$DATA";
1786 const char *fname_stream
= NULL
;
1787 const char *tmp_stream
= ":Updt_\005SummaryInformation:$DATA";
1788 const char *fname_tmp_stream
= NULL
;
1790 union smb_fileinfo finfo
;
1791 union smb_rename rio
;
1794 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1796 fname_stream
= talloc_asprintf(tctx
, "%s%s", fname
, stream
);
1797 fname_tmp_stream
= talloc_asprintf(tctx
, "%s%s", fname
,
1800 /* Create summary info stream */
1801 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1806 /* Create summary info tmp update stream */
1807 ret
= create_file_with_stream(tctx
, cli
, fname_tmp_stream
);
1812 /* Open tmp stream and write to it */
1813 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1814 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1815 io
.ntcreatex
.in
.flags
= 0;
1816 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
1817 io
.ntcreatex
.in
.create_options
= 0;
1818 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1819 io
.ntcreatex
.in
.share_access
= 0;
1820 io
.ntcreatex
.in
.alloc_size
= 0;
1821 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1822 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1823 io
.ntcreatex
.in
.security_flags
= 0;
1824 io
.ntcreatex
.in
.fname
= fname_tmp_stream
;
1826 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1827 CHECK_STATUS(status
, NT_STATUS_OK
);
1828 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1830 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
1831 CHECK_VALUE(retsize
, 9);
1833 /* close the tmp stream. */
1834 smbcli_close(cli
->tree
, fnum
);
1837 /* Delete the current stream */
1838 smbcli_unlink(cli
->tree
, fname_stream
);
1840 /* Do the rename. */
1841 rio
.generic
.level
= RAW_RENAME_RENAME
;
1842 rio
.rename
.in
.pattern1
= fname_tmp_stream
;
1843 rio
.rename
.in
.pattern2
= stream
;
1844 rio
.rename
.in
.attrib
= FILE_ATTRIBUTE_SYSTEM
|
1845 FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
;
1846 status
= smb_raw_rename(cli
->tree
, &rio
);
1847 CHECK_STATUS(status
, NT_STATUS_OK
);
1849 /* Try to open the tmp stream that we just renamed away. */
1850 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1851 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1853 /* Query the base file to make sure it's still there. */
1854 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1855 finfo
.generic
.in
.file
.path
= fname
;
1857 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1858 CHECK_STATUS(status
, NT_STATUS_OK
);
1863 smbcli_close(cli
->tree
, fnum
);
1865 smbcli_unlink(cli
->tree
, fname
);
1867 smbcli_deltree(cli
->tree
, BASEDIR
);
1872 basic testing of streams calls
1874 struct torture_suite
*torture_raw_streams(TALLOC_CTX
*tctx
)
1876 struct torture_suite
*suite
= torture_suite_create(tctx
, "streams");
1878 torture_suite_add_1smb_test(suite
, "dir", test_stream_dir
);
1879 torture_suite_add_1smb_test(suite
, "io", test_stream_io
);
1880 torture_suite_add_1smb_test(suite
, "sharemodes", test_stream_sharemodes
);
1881 torture_suite_add_1smb_test(suite
, "delete", test_stream_delete
);
1882 torture_suite_add_1smb_test(suite
, "names", test_stream_names
);
1883 torture_suite_add_1smb_test(suite
, "names2", test_stream_names2
);
1884 torture_suite_add_1smb_test(suite
, "rename", test_stream_rename
);
1885 torture_suite_add_1smb_test(suite
, "rename2", test_stream_rename2
);
1886 torture_suite_add_1smb_test(suite
, "rename3", test_stream_rename3
);
1887 torture_suite_add_1smb_test(suite
, "createdisp",
1888 test_stream_create_disposition
);
1889 torture_suite_add_1smb_test(suite
, "attr", test_stream_attributes
);
1890 torture_suite_add_1smb_test(suite
, "sumtab", test_stream_summary_tab
);
1893 torture_suite_add_1smb_test(suite
, "LARGESTREAMINFO",
1894 test_stream_large_streaminfo
);