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_FLAG_MAXIMUM_ALLOWED
;
699 io
.ntcreatex
.in
.create_options
= 0;
700 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
701 io
.ntcreatex
.in
.share_access
=
702 NTCREATEX_SHARE_ACCESS_READ
|
703 NTCREATEX_SHARE_ACCESS_WRITE
;
704 io
.ntcreatex
.in
.alloc_size
= 0;
705 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
706 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
707 io
.ntcreatex
.in
.security_flags
= 0;
708 io
.ntcreatex
.in
.fname
= fname
;
710 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
711 CHECK_STATUS(status
, NT_STATUS_OK
);
712 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
714 torture_comment(tctx
, "Adding two EAs to base file\n");
716 sinfo
.generic
.level
= RAW_SFILEINFO_EA_SET
;
717 sinfo
.generic
.in
.file
.fnum
= fnum1
;
718 sinfo
.ea_set
.in
.num_eas
= 2;
719 sinfo
.ea_set
.in
.eas
= talloc_array(tctx
, struct ea_struct
, 2);
720 sinfo
.ea_set
.in
.eas
[0].flags
= 0;
721 sinfo
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
722 sinfo
.ea_set
.in
.eas
[0].value
= data_blob_string_const("VALUE1");
723 sinfo
.ea_set
.in
.eas
[1].flags
= 0;
724 sinfo
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
725 sinfo
.ea_set
.in
.eas
[1].value
= data_blob_string_const("ValueTwo");
727 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
728 CHECK_STATUS(status
, NT_STATUS_OK
);
731 * Make sure the create time of the streams are different from the
735 smbcli_close(cli
->tree
, fnum1
);
737 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
738 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
739 io
.ntcreatex
.in
.flags
= 0;
740 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
741 io
.ntcreatex
.in
.create_options
= 0;
742 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
743 io
.ntcreatex
.in
.share_access
=
744 NTCREATEX_SHARE_ACCESS_READ
|
745 NTCREATEX_SHARE_ACCESS_WRITE
;
746 io
.ntcreatex
.in
.alloc_size
= 0;
747 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
748 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
749 io
.ntcreatex
.in
.security_flags
= 0;
750 io
.ntcreatex
.in
.fname
= sname1
;
752 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
753 CHECK_STATUS(status
, NT_STATUS_OK
);
754 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
756 torture_comment(tctx
, "Adding one EAs to first stream file\n");
758 sinfo
.generic
.level
= RAW_SFILEINFO_EA_SET
;
759 sinfo
.generic
.in
.file
.fnum
= fnum1
;
760 sinfo
.ea_set
.in
.num_eas
= 1;
761 sinfo
.ea_set
.in
.eas
= talloc_array(tctx
, struct ea_struct
, 1);
762 sinfo
.ea_set
.in
.eas
[0].flags
= 0;
763 sinfo
.ea_set
.in
.eas
[0].name
.s
= "STREAMEA";
764 sinfo
.ea_set
.in
.eas
[0].value
= data_blob_string_const("EA_VALUE1");
766 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
767 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
770 * A different stream does not give a sharing violation
773 io
.ntcreatex
.in
.fname
= sname2
;
774 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
775 CHECK_STATUS(status
, NT_STATUS_OK
);
776 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
779 * ... whereas the same stream does with unchanged access/share_access
783 io
.ntcreatex
.in
.fname
= sname1
;
784 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
785 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
786 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
788 io
.ntcreatex
.in
.fname
= sname1b
;
789 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
790 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
792 io
.ntcreatex
.in
.fname
= sname1c
;
793 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
794 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
795 /* w2k returns INVALID_PARAMETER */
796 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
798 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
801 io
.ntcreatex
.in
.fname
= sname1d
;
802 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
803 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
804 /* w2k returns INVALID_PARAMETER */
805 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
807 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
810 io
.ntcreatex
.in
.fname
= sname2
;
811 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
812 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
814 io
.ntcreatex
.in
.fname
= snamew
;
815 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
816 CHECK_STATUS(status
, NT_STATUS_OK
);
817 fnum3
= io
.ntcreatex
.out
.file
.fnum
;
819 io
.ntcreatex
.in
.fname
= snamew2
;
820 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
821 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
823 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
825 smbcli_close(cli
->tree
, fnum1
);
826 smbcli_close(cli
->tree
, fnum2
);
827 smbcli_close(cli
->tree
, fnum3
);
829 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
830 finfo
.generic
.in
.file
.path
= fname
;
831 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
832 CHECK_STATUS(status
, NT_STATUS_OK
);
834 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
836 for (i
=0; i
< 4; i
++) {
838 uint64_t stream_size
;
839 char *path
= talloc_asprintf(tctx
, "%s%s",
842 char *rpath
= talloc_strdup(path
, path
);
843 char *p
= strrchr(rpath
, ':');
851 printf("(%s): i[%u][%s]\n", __location__
, i
, path
);
852 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
853 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
854 SEC_FILE_WRITE_ATTRIBUTE
|
856 io
.ntcreatex
.in
.fname
= path
;
857 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
858 CHECK_STATUS(status
, NT_STATUS_OK
);
859 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
861 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
862 finfo
.generic
.in
.file
.path
= fname
;
863 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
864 CHECK_STATUS(status
, NT_STATUS_OK
);
866 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
867 stinfo
.generic
.in
.file
.fnum
= fnum1
;
868 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
869 CHECK_STATUS(status
, NT_STATUS_OK
);
870 if (!torture_setting_bool(tctx
, "samba3", false)) {
871 CHECK_NTTIME(stinfo
.all_info
.out
.create_time
,
872 finfo
.all_info
.out
.create_time
);
873 CHECK_NTTIME(stinfo
.all_info
.out
.access_time
,
874 finfo
.all_info
.out
.access_time
);
875 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
876 finfo
.all_info
.out
.write_time
);
877 CHECK_NTTIME(stinfo
.all_info
.out
.change_time
,
878 finfo
.all_info
.out
.change_time
);
880 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
881 finfo
.all_info
.out
.attrib
);
882 CHECK_VALUE(stinfo
.all_info
.out
.size
,
883 finfo
.all_info
.out
.size
);
884 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
885 finfo
.all_info
.out
.delete_pending
);
886 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
887 finfo
.all_info
.out
.directory
);
888 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
889 finfo
.all_info
.out
.ea_size
);
891 stinfo
.generic
.level
= RAW_FILEINFO_NAME_INFO
;
892 stinfo
.generic
.in
.file
.fnum
= fnum1
;
893 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
894 CHECK_STATUS(status
, NT_STATUS_OK
);
895 if (!torture_setting_bool(tctx
, "samba3", false)) {
896 CHECK_STR(stinfo
.name_info
.out
.fname
.s
, rpath
);
899 write_time
= finfo
.all_info
.out
.write_time
;
900 write_time
+= i
*1000000;
901 write_time
/= 1000000;
902 write_time
*= 1000000;
905 sinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
906 sinfo
.basic_info
.in
.file
.fnum
= fnum1
;
907 sinfo
.basic_info
.in
.write_time
= write_time
;
908 sinfo
.basic_info
.in
.attrib
= stinfo
.all_info
.out
.attrib
;
909 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
910 CHECK_STATUS(status
, NT_STATUS_OK
);
912 stream_size
= i
*8192;
915 sinfo
.end_of_file_info
.level
= RAW_SFILEINFO_END_OF_FILE_INFO
;
916 sinfo
.end_of_file_info
.in
.file
.fnum
= fnum1
;
917 sinfo
.end_of_file_info
.in
.size
= stream_size
;
918 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
919 CHECK_STATUS(status
, NT_STATUS_OK
);
921 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
922 stinfo
.generic
.in
.file
.fnum
= fnum1
;
923 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
924 CHECK_STATUS(status
, NT_STATUS_OK
);
925 if (!torture_setting_bool(tctx
, "samba3", false)) {
926 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
928 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
929 finfo
.all_info
.out
.attrib
);
931 CHECK_VALUE(stinfo
.all_info
.out
.size
,
933 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
934 finfo
.all_info
.out
.delete_pending
);
935 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
936 finfo
.all_info
.out
.directory
);
937 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
938 finfo
.all_info
.out
.ea_size
);
940 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
942 smbcli_close(cli
->tree
, fnum1
);
946 printf("(%s): testing stream renames\n", __location__
);
947 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
948 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
949 SEC_FILE_WRITE_ATTRIBUTE
|
951 io
.ntcreatex
.in
.fname
= snamer1
;
952 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
953 CHECK_STATUS(status
, NT_STATUS_OK
);
954 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
956 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five1
);
959 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
960 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
961 sinfo
.rename_information
.in
.overwrite
= true;
962 sinfo
.rename_information
.in
.root_fid
= 0;
963 sinfo
.rename_information
.in
.new_name
= ":AfterRename:$DATA";
964 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
965 CHECK_STATUS(status
, NT_STATUS_OK
);
967 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
970 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
971 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
972 sinfo
.rename_information
.in
.overwrite
= false;
973 sinfo
.rename_information
.in
.root_fid
= 0;
974 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
975 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
976 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
978 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
981 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
982 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
983 sinfo
.rename_information
.in
.overwrite
= true;
984 sinfo
.rename_information
.in
.root_fid
= 0;
985 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
986 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
987 if (torture_setting_bool(tctx
, "samba4", false) ||
988 torture_setting_bool(tctx
, "samba3", false)) {
989 /* why should this rename be considered invalid?? */
990 CHECK_STATUS(status
, NT_STATUS_OK
);
991 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
993 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
994 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
998 /* TODO: we need to test more rename combinations */
1001 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
1002 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
1003 if (fnum3
!= -1) smbcli_close(cli
->tree
, fnum3
);
1004 status
= smbcli_unlink(cli
->tree
, fname
);
1005 smbcli_deltree(cli
->tree
, BASEDIR
);
1012 static bool test_stream_names2(struct torture_context
*tctx
,
1013 struct smbcli_state
*cli
)
1017 const char *fname
= BASEDIR
"\\stream_names2.txt";
1022 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1024 printf("(%s) testing stream names\n", __location__
);
1025 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1026 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1027 io
.ntcreatex
.in
.flags
= 0;
1028 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
1029 io
.ntcreatex
.in
.create_options
= 0;
1030 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1031 io
.ntcreatex
.in
.share_access
= 0;
1032 io
.ntcreatex
.in
.alloc_size
= 0;
1033 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1034 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1035 io
.ntcreatex
.in
.security_flags
= 0;
1036 io
.ntcreatex
.in
.fname
= fname
;
1037 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1038 CHECK_STATUS(status
, NT_STATUS_OK
);
1039 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
1041 for (i
=0x01; i
< 0x7F; i
++) {
1042 char *path
= talloc_asprintf(tctx
, "%s:Stream%c0x%02X:$DATA",
1050 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1053 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1058 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1059 io
.ntcreatex
.in
.fname
= path
;
1060 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1061 if (!NT_STATUS_EQUAL(status
, expected
)) {
1062 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1063 __location__
, fname
, isprint(i
)?(char)i
:' ', i
,
1064 isprint(i
)?"":" (not printable)",
1065 nt_errstr(expected
));
1067 CHECK_STATUS(status
, expected
);
1073 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
1074 status
= smbcli_unlink(cli
->tree
, fname
);
1075 smbcli_deltree(cli
->tree
, BASEDIR
);
1079 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1080 check_fnum = true; \
1081 call_name = #call; \
1082 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1083 sfinfo.generic.in.file.fnum = fnum; \
1084 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1085 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1086 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1087 nt_errstr(status), nt_errstr(rightstatus)); \
1090 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1091 finfo1.generic.in.file.fnum = fnum; \
1092 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1093 if (!NT_STATUS_IS_OK(status2)) { \
1094 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1101 static bool test_stream_rename(struct torture_context
*tctx
,
1102 struct smbcli_state
*cli
)
1104 NTSTATUS status
, status2
;
1106 const char *fname
= BASEDIR
"\\stream_rename.txt";
1107 const char *sname1
, *sname2
;
1108 union smb_fileinfo finfo1
;
1109 union smb_setfileinfo sfinfo
;
1113 const char *call_name
;
1115 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1117 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
1118 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1120 printf("(%s) testing stream renames\n", __location__
);
1121 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1122 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1123 io
.ntcreatex
.in
.flags
= 0;
1124 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1125 SEC_FILE_WRITE_ATTRIBUTE
|
1126 SEC_RIGHTS_FILE_ALL
;
1127 io
.ntcreatex
.in
.create_options
= 0;
1128 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1129 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1130 io
.ntcreatex
.in
.alloc_size
= 0;
1131 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1132 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1133 io
.ntcreatex
.in
.security_flags
= 0;
1134 io
.ntcreatex
.in
.fname
= sname1
;
1136 /* Create two streams. */
1137 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1138 CHECK_STATUS(status
, NT_STATUS_OK
);
1139 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1140 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1142 io
.ntcreatex
.in
.fname
= sname2
;
1143 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1144 CHECK_STATUS(status
, NT_STATUS_OK
);
1145 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1147 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1150 * Open the second stream.
1153 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1154 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1155 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1156 CHECK_STATUS(status
, NT_STATUS_OK
);
1157 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1160 * Now rename the second stream onto the first.
1163 ZERO_STRUCT(sfinfo
);
1165 sfinfo
.rename_information
.in
.overwrite
= 1;
1166 sfinfo
.rename_information
.in
.root_fid
= 0;
1167 sfinfo
.rename_information
.in
.new_name
= ":Stream One";
1168 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1171 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1172 status
= smbcli_unlink(cli
->tree
, fname
);
1173 smbcli_deltree(cli
->tree
, BASEDIR
);
1177 static bool test_stream_rename2(struct torture_context
*tctx
,
1178 struct smbcli_state
*cli
)
1182 const char *fname1
= BASEDIR
"\\stream.txt";
1183 const char *fname2
= BASEDIR
"\\stream2.txt";
1184 const char *stream_name1
= ":Stream One:$DATA";
1185 const char *stream_name2
= ":Stream Two:$DATA";
1186 const char *stream_name_default
= "::$DATA";
1191 union smb_setfileinfo sinfo
;
1192 union smb_rename rio
;
1194 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1196 sname1
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream One");
1197 sname2
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream Two");
1199 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1200 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1201 io
.ntcreatex
.in
.flags
= 0;
1202 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1203 SEC_STD_DELETE
|SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1204 io
.ntcreatex
.in
.create_options
= 0;
1205 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1206 io
.ntcreatex
.in
.share_access
= (NTCREATEX_SHARE_ACCESS_READ
|
1207 NTCREATEX_SHARE_ACCESS_WRITE
|
1208 NTCREATEX_SHARE_ACCESS_DELETE
);
1209 io
.ntcreatex
.in
.alloc_size
= 0;
1210 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1211 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1212 io
.ntcreatex
.in
.security_flags
= 0;
1213 io
.ntcreatex
.in
.fname
= sname1
;
1215 /* Open/create new stream. */
1216 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1217 CHECK_STATUS(status
, NT_STATUS_OK
);
1219 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1222 * Check raw rename with <base>:<stream>.
1224 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1226 rio
.generic
.level
= RAW_RENAME_NTRENAME
;
1227 rio
.ntrename
.in
.old_name
= sname1
;
1228 rio
.ntrename
.in
.new_name
= sname2
;
1229 rio
.ntrename
.in
.attrib
= 0;
1230 rio
.ntrename
.in
.cluster_size
= 0;
1231 rio
.ntrename
.in
.flags
= RENAME_FLAG_RENAME
;
1232 status
= smb_raw_rename(cli
->tree
, &rio
);
1233 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1236 * Check raw rename to the default stream using :<stream>.
1238 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1240 rio
.ntrename
.in
.new_name
= stream_name_default
;
1241 status
= smb_raw_rename(cli
->tree
, &rio
);
1242 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
1245 * Check raw rename using :<stream>.
1247 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1249 rio
.ntrename
.in
.new_name
= stream_name2
;
1250 status
= smb_raw_rename(cli
->tree
, &rio
);
1251 CHECK_STATUS(status
, NT_STATUS_OK
);
1254 * Check raw rename of a stream to a file.
1256 printf("(%s) Checking NTRENAME of a stream to a file\n",
1258 rio
.ntrename
.in
.old_name
= sname2
;
1259 rio
.ntrename
.in
.new_name
= fname2
;
1260 status
= smb_raw_rename(cli
->tree
, &rio
);
1261 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1264 * Check raw rename of a file to a stream.
1266 printf("(%s) Checking NTRENAME of a file to a stream\n",
1269 /* Create the file. */
1270 io
.ntcreatex
.in
.fname
= fname2
;
1271 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1272 CHECK_STATUS(status
, NT_STATUS_OK
);
1273 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1275 /* Try the rename. */
1276 rio
.ntrename
.in
.old_name
= fname2
;
1277 rio
.ntrename
.in
.new_name
= sname1
;
1278 status
= smb_raw_rename(cli
->tree
, &rio
);
1279 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
1282 * Reopen the stream for trans2 renames.
1284 io
.ntcreatex
.in
.fname
= sname2
;
1285 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1286 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1287 CHECK_STATUS(status
, NT_STATUS_OK
);
1288 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1291 * Check trans2 rename of a stream using :<stream>.
1293 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1296 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1297 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1298 sinfo
.rename_information
.in
.overwrite
= 1;
1299 sinfo
.rename_information
.in
.root_fid
= 0;
1300 sinfo
.rename_information
.in
.new_name
= stream_name1
;
1301 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1302 CHECK_STATUS(status
, NT_STATUS_OK
);
1305 * Check trans2 rename of an overwriting stream using :<stream>.
1307 printf("(%s) Checking trans2 rename of an overwriting stream using "
1308 ":<stream>\n", __location__
);
1310 /* Create second stream. */
1311 io
.ntcreatex
.in
.fname
= sname2
;
1312 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1313 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1314 CHECK_STATUS(status
, NT_STATUS_OK
);
1315 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1317 /* Rename the first stream onto the second. */
1318 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1319 sinfo
.rename_information
.in
.new_name
= stream_name2
;
1320 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1321 CHECK_STATUS(status
, NT_STATUS_OK
);
1323 smbcli_close(cli
->tree
, fnum
);
1326 * Reopen the stream with the new name.
1328 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1329 io
.ntcreatex
.in
.fname
= sname2
;
1330 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1331 CHECK_STATUS(status
, NT_STATUS_OK
);
1332 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1335 * Check trans2 rename of a stream using <base>:<stream>.
1337 printf("(%s) Checking trans2 rename of a stream using "
1338 "<base>:<stream>\n", __location__
);
1339 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1340 sinfo
.rename_information
.in
.new_name
= sname1
;
1341 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1342 CHECK_STATUS(status
, NT_STATUS_NOT_SUPPORTED
);
1345 * Samba3 doesn't currently support renaming a stream to the default
1346 * stream. This test does pass on windows.
1348 if (torture_setting_bool(tctx
, "samba3", false) ||
1349 torture_setting_bool(tctx
, "samba4", false)) {
1354 * Check trans2 rename to the default stream using :<stream>.
1356 printf("(%s) Checking trans2 rename to defaualt stream using "
1357 ":<stream>\n", __location__
);
1358 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1359 sinfo
.rename_information
.in
.new_name
= stream_name_default
;
1360 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1361 CHECK_STATUS(status
, NT_STATUS_OK
);
1363 smbcli_close(cli
->tree
, fnum
);
1366 smbcli_close(cli
->tree
, fnum
);
1367 status
= smbcli_unlink(cli
->tree
, fname1
);
1368 status
= smbcli_unlink(cli
->tree
, fname2
);
1369 smbcli_deltree(cli
->tree
, BASEDIR
);
1376 static bool test_stream_rename3(struct torture_context
*tctx
,
1377 struct smbcli_state
*cli
)
1379 NTSTATUS status
, status2
;
1381 const char *fname
= BASEDIR
"\\stream_rename.txt";
1382 const char *sname1
, *sname2
;
1383 union smb_fileinfo finfo1
;
1384 union smb_setfileinfo sfinfo
;
1389 const char *call_name
;
1391 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1393 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "MStream Two:$DATA");
1394 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1396 printf("(%s) testing stream renames\n", __location__
);
1397 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1398 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1399 io
.ntcreatex
.in
.flags
= 0;
1400 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1401 SEC_FILE_WRITE_ATTRIBUTE
|
1402 SEC_RIGHTS_FILE_ALL
;
1403 io
.ntcreatex
.in
.create_options
= 0;
1404 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1405 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1406 NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1407 io
.ntcreatex
.in
.alloc_size
= 0;
1408 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1409 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1410 io
.ntcreatex
.in
.security_flags
= 0;
1411 io
.ntcreatex
.in
.fname
= sname1
;
1413 /* Create two streams. */
1414 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1415 CHECK_STATUS(status
, NT_STATUS_OK
);
1416 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1417 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1419 io
.ntcreatex
.in
.fname
= sname2
;
1420 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1421 CHECK_STATUS(status
, NT_STATUS_OK
);
1422 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1424 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1426 /* open the second stream. */
1427 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1428 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1429 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1430 CHECK_STATUS(status
, NT_STATUS_OK
);
1431 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1433 /* Keep a handle to the first stream open. */
1434 io
.ntcreatex
.in
.fname
= sname1
;
1435 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1436 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1437 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1438 CHECK_STATUS(status
, NT_STATUS_OK
);
1439 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
1441 ZERO_STRUCT(sfinfo
);
1442 sfinfo
.rename_information
.in
.overwrite
= 1;
1443 sfinfo
.rename_information
.in
.root_fid
= 0;
1444 sfinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1445 if (torture_setting_bool(tctx
, "samba4", false) ||
1446 torture_setting_bool(tctx
, "samba3", false)) {
1447 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1449 CHECK_CALL_FNUM(RENAME_INFORMATION
,
1450 NT_STATUS_INVALID_PARAMETER
);
1455 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1456 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
1457 status
= smbcli_unlink(cli
->tree
, fname
);
1458 smbcli_deltree(cli
->tree
, BASEDIR
);
1462 static bool create_file_with_stream(struct torture_context
*tctx
,
1463 struct smbcli_state
*cli
,
1470 /* Create a file with a stream */
1471 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1472 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1473 io
.ntcreatex
.in
.flags
= 0;
1474 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1475 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1476 io
.ntcreatex
.in
.create_options
= 0;
1477 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1478 io
.ntcreatex
.in
.share_access
= 0;
1479 io
.ntcreatex
.in
.alloc_size
= 0;
1480 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1481 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1482 io
.ntcreatex
.in
.security_flags
= 0;
1483 io
.ntcreatex
.in
.fname
= stream
;
1485 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1486 CHECK_STATUS(status
, NT_STATUS_OK
);
1489 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1493 /* Test how streams interact with create dispositions */
1494 static bool test_stream_create_disposition(struct torture_context
*tctx
,
1495 struct smbcli_state
*cli
)
1499 const char *fname
= BASEDIR
"\\stream.txt";
1500 const char *stream
= "Stream One:$DATA";
1501 const char *fname_stream
;
1502 const char *default_stream_name
= "::$DATA";
1503 const char *stream_list
[2];
1507 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1509 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1511 stream_list
[0] = talloc_asprintf(tctx
, ":%s", stream
);
1512 stream_list
[1] = default_stream_name
;
1514 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1518 /* Open the base file with OPEN */
1519 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1520 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1521 io
.ntcreatex
.in
.flags
= 0;
1522 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1523 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1524 io
.ntcreatex
.in
.create_options
= 0;
1525 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1526 io
.ntcreatex
.in
.share_access
= 0;
1527 io
.ntcreatex
.in
.alloc_size
= 0;
1528 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1529 io
.ntcreatex
.in
.security_flags
= 0;
1530 io
.ntcreatex
.in
.fname
= fname
;
1533 * check ntcreatex open: sanity check
1535 printf("(%s) Checking ntcreatex disp: open\n", __location__
);
1536 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1537 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1538 CHECK_STATUS(status
, NT_STATUS_OK
);
1539 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1540 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1545 * check ntcreatex overwrite
1547 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__
);
1548 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
1549 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1550 CHECK_STATUS(status
, NT_STATUS_OK
);
1551 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1552 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1557 * check ntcreatex overwrite_if
1559 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__
);
1560 smbcli_unlink(cli
->tree
, fname
);
1561 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1565 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1566 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1567 CHECK_STATUS(status
, NT_STATUS_OK
);
1568 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1569 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1574 * check ntcreatex supersede
1576 printf("(%s) Checking ntcreatex disp: supersede\n", __location__
);
1577 smbcli_unlink(cli
->tree
, fname
);
1578 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1582 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
1583 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1584 CHECK_STATUS(status
, NT_STATUS_OK
);
1585 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1586 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1591 * check ntcreatex overwrite_if on a stream.
1593 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1595 smbcli_unlink(cli
->tree
, fname
);
1596 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1600 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1601 io
.ntcreatex
.in
.fname
= fname_stream
;
1602 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1603 CHECK_STATUS(status
, NT_STATUS_OK
);
1604 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1605 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1610 * check openx overwrite_if
1612 printf("(%s) Checking openx disp: overwrite_if\n", __location__
);
1613 smbcli_unlink(cli
->tree
, fname
);
1614 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1618 io
.openx
.level
= RAW_OPEN_OPENX
;
1619 io
.openx
.in
.flags
= OPENX_FLAGS_ADDITIONAL_INFO
;
1620 io
.openx
.in
.open_mode
= OPENX_MODE_ACCESS_RDWR
| OPEN_FLAGS_DENY_NONE
;
1621 io
.openx
.in
.search_attrs
= 0;
1622 io
.openx
.in
.file_attrs
= 0;
1623 io
.openx
.in
.write_time
= 0;
1624 io
.openx
.in
.size
= 1024*1024;
1625 io
.openx
.in
.timeout
= 0;
1626 io
.openx
.in
.fname
= fname
;
1628 io
.openx
.in
.open_func
= OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
;
1629 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1630 CHECK_STATUS(status
, NT_STATUS_OK
);
1631 smbcli_close(cli
->tree
, io
.openx
.out
.file
.fnum
);
1632 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1639 smbcli_close(cli
->tree
, fnum
);
1640 smbcli_unlink(cli
->tree
, fname
);
1641 smbcli_deltree(cli
->tree
, BASEDIR
);
1646 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1647 static bool test_stream_large_streaminfo(struct torture_context
*tctx
,
1648 struct smbcli_state
*cli
)
1650 #define LONG_STREAM_SIZE 2
1652 const char *fname
= BASEDIR
"\\stream.txt";
1653 const char *fname_stream
;
1657 union smb_fileinfo finfo
;
1659 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1661 lstream_name
= talloc_array(tctx
, char, LONG_STREAM_SIZE
);
1663 for (i
= 0; i
< LONG_STREAM_SIZE
- 1; i
++) {
1664 lstream_name
[i
] = (char)('a' + i
%26);
1666 lstream_name
[LONG_STREAM_SIZE
- 1] = '\0';
1668 torture_comment(tctx
, "(%s) Creating a file with a lot of streams\n", __location__
);
1669 for (i
= 0; i
< 10000; i
++) {
1670 fname_stream
= talloc_asprintf(tctx
, "%s:%s%d", fname
,
1672 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1678 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
1679 finfo
.generic
.in
.file
.path
= fname
;
1681 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1682 CHECK_STATUS(status
, STATUS_BUFFER_OVERFLOW
);
1685 smbcli_unlink(cli
->tree
, fname
);
1686 smbcli_deltree(cli
->tree
, BASEDIR
);
1691 /* Test the effect of setting attributes on a stream. */
1692 static bool test_stream_attributes(struct torture_context
*tctx
,
1693 struct smbcli_state
*cli
)
1698 const char *fname
= BASEDIR
"\\stream_attr.txt";
1699 const char *stream
= "Stream One:$DATA";
1700 const char *fname_stream
;
1702 union smb_fileinfo finfo
;
1703 union smb_setfileinfo sfinfo
;
1704 time_t basetime
= (time(NULL
) - 86400) & ~1;
1706 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1708 torture_comment(tctx
, "(%s) testing attribute setting on stream\n", __location__
);
1710 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1712 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1713 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1719 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1720 finfo
.generic
.in
.file
.path
= fname
;
1721 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1722 CHECK_STATUS(status
, NT_STATUS_OK
);
1724 torture_assert_int_equal_goto(tctx
, finfo
.all_info
.out
.attrib
& ~FILE_ATTRIBUTE_NONINDEXED
, FILE_ATTRIBUTE_ARCHIVE
, ret
, done
, "attrib incorrect");
1726 /* Now open the stream name. */
1728 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1729 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1730 io
.ntcreatex
.in
.flags
= 0;
1731 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1732 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
|SEC_FILE_WRITE_ATTRIBUTE
);
1733 io
.ntcreatex
.in
.create_options
= 0;
1734 io
.ntcreatex
.in
.file_attr
= 0;
1735 io
.ntcreatex
.in
.share_access
= 0;
1736 io
.ntcreatex
.in
.alloc_size
= 0;
1737 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1738 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1739 io
.ntcreatex
.in
.security_flags
= 0;
1740 io
.ntcreatex
.in
.fname
= fname_stream
;
1742 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1743 CHECK_STATUS(status
, NT_STATUS_OK
);
1745 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1747 /* Change the attributes + time on the stream fnum. */
1748 ZERO_STRUCT(sfinfo
);
1749 sfinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_READONLY
;
1750 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, basetime
);
1752 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1753 sfinfo
.generic
.in
.file
.fnum
= fnum
;
1754 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
1755 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OK
, ret
, done
, "smb_raw_setfileinfo failed");
1757 smbcli_close(cli
->tree
, fnum
);
1761 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
1762 finfo
.generic
.in
.file
.path
= fname
;
1763 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1764 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_OK
, ret
, done
, "smb_raw_pathinfo failed");
1766 torture_assert_int_equal_goto(tctx
, finfo
.all_info
.out
.attrib
& ~FILE_ATTRIBUTE_NONINDEXED
, FILE_ATTRIBUTE_READONLY
, ret
, done
, "attrib incorrect");
1768 torture_assert_int_equal_goto(tctx
, nt_time_to_unix(finfo
.all_info
.out
.write_time
), basetime
, ret
, done
, "time incorrect");
1773 smbcli_close(cli
->tree
, fnum
);
1775 smbcli_unlink(cli
->tree
, fname
);
1776 smbcli_deltree(cli
->tree
, BASEDIR
);
1781 * A rough approximation of how a windows client creates the streams for use
1782 * in the summary tab.
1784 static bool test_stream_summary_tab(struct torture_context
*tctx
,
1785 struct smbcli_state
*cli
)
1790 const char *fname
= BASEDIR
"\\stream_summary.txt";
1791 const char *stream
= ":\005SummaryInformation:$DATA";
1792 const char *fname_stream
= NULL
;
1793 const char *tmp_stream
= ":Updt_\005SummaryInformation:$DATA";
1794 const char *fname_tmp_stream
= NULL
;
1796 union smb_fileinfo finfo
;
1797 union smb_rename rio
;
1800 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1802 fname_stream
= talloc_asprintf(tctx
, "%s%s", fname
, stream
);
1803 fname_tmp_stream
= talloc_asprintf(tctx
, "%s%s", fname
,
1806 /* Create summary info stream */
1807 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1812 /* Create summary info tmp update stream */
1813 ret
= create_file_with_stream(tctx
, cli
, fname_tmp_stream
);
1818 /* Open tmp stream and write to it */
1819 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1820 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1821 io
.ntcreatex
.in
.flags
= 0;
1822 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
1823 io
.ntcreatex
.in
.create_options
= 0;
1824 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1825 io
.ntcreatex
.in
.share_access
= 0;
1826 io
.ntcreatex
.in
.alloc_size
= 0;
1827 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1828 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1829 io
.ntcreatex
.in
.security_flags
= 0;
1830 io
.ntcreatex
.in
.fname
= fname_tmp_stream
;
1832 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1833 CHECK_STATUS(status
, NT_STATUS_OK
);
1834 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1836 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
1837 CHECK_VALUE(retsize
, 9);
1839 /* close the tmp stream. */
1840 smbcli_close(cli
->tree
, fnum
);
1843 /* Delete the current stream */
1844 smbcli_unlink(cli
->tree
, fname_stream
);
1846 /* Do the rename. */
1847 rio
.generic
.level
= RAW_RENAME_RENAME
;
1848 rio
.rename
.in
.pattern1
= fname_tmp_stream
;
1849 rio
.rename
.in
.pattern2
= stream
;
1850 rio
.rename
.in
.attrib
= FILE_ATTRIBUTE_SYSTEM
|
1851 FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
;
1852 status
= smb_raw_rename(cli
->tree
, &rio
);
1853 CHECK_STATUS(status
, NT_STATUS_OK
);
1855 /* Try to open the tmp stream that we just renamed away. */
1856 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1857 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1859 /* Query the base file to make sure it's still there. */
1860 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1861 finfo
.generic
.in
.file
.path
= fname
;
1863 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1864 CHECK_STATUS(status
, NT_STATUS_OK
);
1869 smbcli_close(cli
->tree
, fnum
);
1871 smbcli_unlink(cli
->tree
, fname
);
1873 smbcli_deltree(cli
->tree
, BASEDIR
);
1878 basic testing of streams calls
1880 struct torture_suite
*torture_raw_streams(TALLOC_CTX
*tctx
)
1882 struct torture_suite
*suite
= torture_suite_create(tctx
, "streams");
1884 torture_suite_add_1smb_test(suite
, "dir", test_stream_dir
);
1885 torture_suite_add_1smb_test(suite
, "io", test_stream_io
);
1886 torture_suite_add_1smb_test(suite
, "sharemodes", test_stream_sharemodes
);
1887 torture_suite_add_1smb_test(suite
, "delete", test_stream_delete
);
1888 torture_suite_add_1smb_test(suite
, "names", test_stream_names
);
1889 torture_suite_add_1smb_test(suite
, "names2", test_stream_names2
);
1890 torture_suite_add_1smb_test(suite
, "rename", test_stream_rename
);
1891 torture_suite_add_1smb_test(suite
, "rename2", test_stream_rename2
);
1892 torture_suite_add_1smb_test(suite
, "rename3", test_stream_rename3
);
1893 torture_suite_add_1smb_test(suite
, "createdisp",
1894 test_stream_create_disposition
);
1895 torture_suite_add_1smb_test(suite
, "attr", test_stream_attributes
);
1896 torture_suite_add_1smb_test(suite
, "sumtab", test_stream_summary_tab
);
1899 torture_suite_add_1smb_test(suite
, "LARGESTREAMINFO",
1900 test_stream_large_streaminfo
);