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 if (!torture_setup_dir(cli
, BASEDIR
)) {
205 basedir_data
= talloc_asprintf(tctx
, "%s::$DATA", BASEDIR
);
206 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
208 printf("(%s) opening non-existant directory stream\n", __location__
);
209 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
210 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
211 io
.ntcreatex
.in
.flags
= 0;
212 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
213 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
214 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
215 io
.ntcreatex
.in
.share_access
= 0;
216 io
.ntcreatex
.in
.alloc_size
= 0;
217 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
218 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
219 io
.ntcreatex
.in
.security_flags
= 0;
220 io
.ntcreatex
.in
.fname
= sname1
;
221 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
222 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
224 printf("(%s) opening basedir stream\n", __location__
);
225 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
226 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
227 io
.ntcreatex
.in
.flags
= 0;
228 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
229 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
230 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_DIRECTORY
;
231 io
.ntcreatex
.in
.share_access
= 0;
232 io
.ntcreatex
.in
.alloc_size
= 0;
233 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
234 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
235 io
.ntcreatex
.in
.security_flags
= 0;
236 io
.ntcreatex
.in
.fname
= basedir_data
;
237 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
238 CHECK_STATUS(status
, NT_STATUS_NOT_A_DIRECTORY
);
240 printf("(%s) opening basedir ::$DATA stream\n", __location__
);
241 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
242 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
243 io
.ntcreatex
.in
.flags
= 0x10;
244 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
245 io
.ntcreatex
.in
.create_options
= 0;
246 io
.ntcreatex
.in
.file_attr
= 0;
247 io
.ntcreatex
.in
.share_access
= 0;
248 io
.ntcreatex
.in
.alloc_size
= 0;
249 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
250 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
251 io
.ntcreatex
.in
.security_flags
= 0;
252 io
.ntcreatex
.in
.fname
= basedir_data
;
253 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
254 CHECK_STATUS(status
, NT_STATUS_FILE_IS_A_DIRECTORY
);
256 printf("(%s) list the streams on the basedir\n", __location__
);
257 ret
&= check_stream_list(tctx
, cli
, BASEDIR
, 0, NULL
);
259 smbcli_deltree(cli
->tree
, BASEDIR
);
264 test basic behavior of streams on directories
266 static bool test_stream_io(struct torture_context
*tctx
,
267 struct smbcli_state
*cli
)
271 const char *fname
= BASEDIR
"\\stream.txt";
272 const char *sname1
, *sname2
;
277 const char *one
[] = { "::$DATA" };
278 const char *two
[] = { "::$DATA", ":Second Stream:$DATA" };
279 const char *three
[] = { "::$DATA", ":Stream One:$DATA",
280 ":Second Stream:$DATA" };
282 if (!torture_setup_dir(cli
, BASEDIR
)) {
286 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
287 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
289 printf("(%s) creating a stream on a non-existant file\n", __location__
);
290 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
291 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
292 io
.ntcreatex
.in
.flags
= 0;
293 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
294 io
.ntcreatex
.in
.create_options
= 0;
295 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
296 io
.ntcreatex
.in
.share_access
= 0;
297 io
.ntcreatex
.in
.alloc_size
= 0;
298 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
299 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
300 io
.ntcreatex
.in
.security_flags
= 0;
301 io
.ntcreatex
.in
.fname
= sname1
;
302 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
303 CHECK_STATUS(status
, NT_STATUS_OK
);
304 fnum
= io
.ntcreatex
.out
.file
.fnum
;
306 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", NULL
);
308 printf("(%s) check that open of base file is allowed\n", __location__
);
309 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
310 io
.ntcreatex
.in
.fname
= fname
;
311 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
312 CHECK_STATUS(status
, NT_STATUS_OK
);
313 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
315 printf("(%s) writing to stream\n", __location__
);
316 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
317 CHECK_VALUE(retsize
, 9);
319 smbcli_close(cli
->tree
, fnum
);
321 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test data");
323 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
324 io
.ntcreatex
.in
.fname
= sname1
;
325 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
326 CHECK_STATUS(status
, NT_STATUS_OK
);
327 fnum
= io
.ntcreatex
.out
.file
.fnum
;
329 printf("(%s) modifying stream\n", __location__
);
330 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "MORE DATA ", 5, 10);
331 CHECK_VALUE(retsize
, 10);
333 smbcli_close(cli
->tree
, fnum
);
335 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$FOO", NULL
);
337 printf("(%s) creating a stream2 on a existing file\n", __location__
);
338 io
.ntcreatex
.in
.fname
= sname2
;
339 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
340 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
341 CHECK_STATUS(status
, NT_STATUS_OK
);
342 fnum
= io
.ntcreatex
.out
.file
.fnum
;
344 printf("(%s) modifying stream\n", __location__
);
345 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "SECOND STREAM", 0, 13);
346 CHECK_VALUE(retsize
, 13);
348 smbcli_close(cli
->tree
, fnum
);
350 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One", "test MORE DATA ");
351 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:$DATA", "test MORE DATA ");
352 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Stream One:", NULL
);
353 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream", "SECOND STREAM");
354 ret
&= check_stream(cli
, __location__
, tctx
, fname
,
355 "SECOND STREAM:$DATA", "SECOND STREAM");
356 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$DATA", "SECOND STREAM");
357 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:", NULL
);
358 ret
&= check_stream(cli
, __location__
, tctx
, fname
, "Second Stream:$FOO", NULL
);
360 check_stream_list(tctx
, cli
, fname
, 3, three
);
362 printf("(%s) deleting stream\n", __location__
);
363 status
= smbcli_unlink(cli
->tree
, sname1
);
364 CHECK_STATUS(status
, NT_STATUS_OK
);
366 check_stream_list(tctx
, cli
, fname
, 2, two
);
368 printf("(%s) delete a stream via delete-on-close\n", __location__
);
369 io
.ntcreatex
.in
.fname
= sname2
;
370 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
371 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
372 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
373 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
375 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
376 CHECK_STATUS(status
, NT_STATUS_OK
);
377 fnum
= io
.ntcreatex
.out
.file
.fnum
;
379 smbcli_close(cli
->tree
, fnum
);
380 status
= smbcli_unlink(cli
->tree
, sname2
);
381 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
383 check_stream_list(tctx
, cli
, fname
, 1, one
);
385 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
386 io
.ntcreatex
.in
.fname
= sname1
;
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
);
390 io
.ntcreatex
.in
.fname
= sname2
;
391 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
392 CHECK_STATUS(status
, NT_STATUS_OK
);
393 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
395 printf("(%s) deleting file\n", __location__
);
396 status
= smbcli_unlink(cli
->tree
, fname
);
397 CHECK_STATUS(status
, NT_STATUS_OK
);
400 smbcli_close(cli
->tree
, fnum
);
401 smbcli_deltree(cli
->tree
, BASEDIR
);
406 test stream sharemodes
408 static bool test_stream_sharemodes(struct torture_context
*tctx
,
409 struct smbcli_state
*cli
)
413 const char *fname
= BASEDIR
"\\stream.txt";
414 const char *sname1
, *sname2
;
419 if (!torture_setup_dir(cli
, BASEDIR
)) {
423 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
424 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
426 printf("(%s) testing stream share mode conflicts\n", __location__
);
427 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
428 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
429 io
.ntcreatex
.in
.flags
= 0;
430 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
431 io
.ntcreatex
.in
.create_options
= 0;
432 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
433 io
.ntcreatex
.in
.share_access
= 0;
434 io
.ntcreatex
.in
.alloc_size
= 0;
435 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
436 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
437 io
.ntcreatex
.in
.security_flags
= 0;
438 io
.ntcreatex
.in
.fname
= sname1
;
440 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
441 CHECK_STATUS(status
, NT_STATUS_OK
);
442 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
445 * A different stream does not give a sharing violation
448 io
.ntcreatex
.in
.fname
= sname2
;
449 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
450 CHECK_STATUS(status
, NT_STATUS_OK
);
451 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
454 * ... whereas the same stream does with unchanged access/share_access
458 io
.ntcreatex
.in
.fname
= sname1
;
459 io
.ntcreatex
.in
.open_disposition
= 0;
460 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
461 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
463 io
.ntcreatex
.in
.fname
= sname2
;
464 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
465 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
468 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
469 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
470 status
= smbcli_unlink(cli
->tree
, fname
);
471 smbcli_deltree(cli
->tree
, BASEDIR
);
476 * Test FILE_SHARE_DELETE on streams
478 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
479 * with SEC_STD_DELETE.
481 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
482 * be opened with SEC_STD_DELETE.
484 * A stream held open with FILE_SHARE_DELETE allows the file to be
485 * deleted. After the main file is deleted, access to the open file descriptor
486 * still works, but all name-based access to both the main file as well as the
487 * stream is denied with DELETE ending.
489 * This means, an open of the main file with SEC_STD_DELETE should walk all
490 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
491 * SHARING_VIOLATION, the main open fails.
493 * Closing the main file after delete_on_close has been set does not really
494 * unlink it but leaves the corresponding share mode entry with
495 * delete_on_close being set around until all streams are closed.
497 * Opening a stream must also look at the main file's share mode entry, look
498 * at the delete_on_close bit and potentially return DELETE_PENDING.
501 static bool test_stream_delete(struct torture_context
*tctx
,
502 struct smbcli_state
*cli
)
506 const char *fname
= BASEDIR
"\\stream.txt";
512 union smb_fileinfo finfo
;
514 if (!torture_setup_dir(cli
, BASEDIR
)) {
518 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
520 printf("(%s) opening non-existant file stream\n", __location__
);
521 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
522 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
523 io
.ntcreatex
.in
.flags
= 0;
524 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
525 io
.ntcreatex
.in
.create_options
= 0;
526 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
527 io
.ntcreatex
.in
.share_access
= 0;
528 io
.ntcreatex
.in
.alloc_size
= 0;
529 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
530 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
531 io
.ntcreatex
.in
.security_flags
= 0;
532 io
.ntcreatex
.in
.fname
= sname1
;
534 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
535 CHECK_STATUS(status
, NT_STATUS_OK
);
536 fnum
= io
.ntcreatex
.out
.file
.fnum
;
538 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
539 CHECK_VALUE(retsize
, 9);
542 * One stream opened without FILE_SHARE_DELETE prevents the main file
543 * to be deleted or even opened with DELETE access
546 status
= smbcli_unlink(cli
->tree
, fname
);
547 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
549 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
550 io
.ntcreatex
.in
.fname
= fname
;
551 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
552 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
553 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
555 smbcli_close(cli
->tree
, fnum
);
558 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
561 io
.ntcreatex
.in
.fname
= sname1
;
562 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
563 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
;
564 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
565 CHECK_STATUS(status
, NT_STATUS_OK
);
566 fnum
= io
.ntcreatex
.out
.file
.fnum
;
568 status
= smbcli_unlink(cli
->tree
, fname
);
569 CHECK_STATUS(status
, NT_STATUS_OK
);
572 * file access still works on the stream while the main file is closed
575 retsize
= smbcli_read(cli
->tree
, fnum
, buf
, 0, 9);
576 CHECK_VALUE(retsize
, 9);
578 finfo
.generic
.level
= RAW_FILEINFO_STANDARD
;
579 finfo
.generic
.in
.file
.path
= fname
;
582 * name-based access to both the main file and the stream does not
583 * work anymore but gives DELETE_PENDING
586 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
587 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
590 * older S3 doesn't do this
592 finfo
.generic
.in
.file
.path
= sname1
;
593 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
594 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
597 * fd-based qfileinfo on the stream still works, the stream does not
598 * have the delete-on-close bit set. This could mean that open on the
599 * stream first opens the main file
602 finfo
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
603 finfo
.all_info
.in
.file
.fnum
= fnum
;
605 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo
);
606 CHECK_STATUS(status
, NT_STATUS_OK
);
608 /* w2k and w2k3 return 0 and w2k8 returns 1 */
609 if (TARGET_IS_WINXP(tctx
) || TARGET_IS_W2K3(tctx
) ||
610 TARGET_IS_SAMBA3(tctx
)) {
611 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 0);
613 CHECK_VALUE(finfo
.all_info
.out
.delete_pending
, 1);
616 smbcli_close(cli
->tree
, fnum
);
619 * After closing the stream the file is really gone.
622 finfo
.generic
.in
.file
.path
= fname
;
623 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
624 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
626 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
628 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
629 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
630 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
631 CHECK_STATUS(status
, NT_STATUS_OK
);
632 fnum
= io
.ntcreatex
.out
.file
.fnum
;
634 finfo
.generic
.in
.file
.path
= fname
;
635 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
636 CHECK_STATUS(status
, NT_STATUS_OK
);
638 smbcli_close(cli
->tree
, fnum
);
640 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
641 CHECK_STATUS(status
, NT_STATUS_OK
);
643 smbcli_close(cli
->tree
, fnum
);
644 smbcli_unlink(cli
->tree
, fname
);
645 smbcli_deltree(cli
->tree
, BASEDIR
);
652 static bool test_stream_names(struct torture_context
*tctx
,
653 struct smbcli_state
*cli
)
657 union smb_fileinfo finfo
;
658 union smb_fileinfo stinfo
;
659 union smb_setfileinfo sinfo
;
660 const char *fname
= BASEDIR
"\\stream_names.txt";
661 const char *sname1
, *sname1b
, *sname1c
, *sname1d
;
662 const char *sname2
, *snamew
, *snamew2
;
663 const char *snamer1
, *snamer2
;
669 const char *four
[4] = {
671 ":\x05Stream\n One:$DATA",
672 ":MStream Two:$DATA",
675 const char *five1
[5] = {
677 ":\x05Stream\n One:$DATA",
678 ":BeforeRename:$DATA",
679 ":MStream Two:$DATA",
682 const char *five2
[5] = {
684 ":\x05Stream\n One:$DATA",
685 ":AfterRename:$DATA",
686 ":MStream Two:$DATA",
690 if (!torture_setup_dir(cli
, BASEDIR
)) {
694 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "\x05Stream\n One");
695 sname1b
= talloc_asprintf(tctx
, "%s:", sname1
);
696 sname1c
= talloc_asprintf(tctx
, "%s:$FOO", sname1
);
697 sname1d
= talloc_asprintf(tctx
, "%s:?D*a", sname1
);
698 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "MStream Two");
699 snamew
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "?Stream*");
700 snamew2
= talloc_asprintf(tctx
, "%s\\stream*:%s:$DATA", BASEDIR
, "?Stream*");
701 snamer1
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "BeforeRename");
702 snamer2
= talloc_asprintf(tctx
, "%s:%s:$DATA", fname
, "AfterRename");
704 printf("(%s) testing stream names\n", __location__
);
705 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
706 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
707 io
.ntcreatex
.in
.flags
= 0;
708 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
709 io
.ntcreatex
.in
.create_options
= 0;
710 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
711 io
.ntcreatex
.in
.share_access
= 0;
712 io
.ntcreatex
.in
.alloc_size
= 0;
713 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
714 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
715 io
.ntcreatex
.in
.security_flags
= 0;
716 io
.ntcreatex
.in
.fname
= fname
;
718 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
719 CHECK_STATUS(status
, NT_STATUS_OK
);
720 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
723 * Make sure the create time of the streams are different from the
727 smbcli_close(cli
->tree
, fnum1
);
729 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
730 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
731 io
.ntcreatex
.in
.flags
= 0;
732 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
733 io
.ntcreatex
.in
.create_options
= 0;
734 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
735 io
.ntcreatex
.in
.share_access
= 0;
736 io
.ntcreatex
.in
.alloc_size
= 0;
737 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
738 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
739 io
.ntcreatex
.in
.security_flags
= 0;
740 io
.ntcreatex
.in
.fname
= sname1
;
742 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
743 CHECK_STATUS(status
, NT_STATUS_OK
);
744 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
747 * A different stream does not give a sharing violation
750 io
.ntcreatex
.in
.fname
= sname2
;
751 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
752 CHECK_STATUS(status
, NT_STATUS_OK
);
753 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
756 * ... whereas the same stream does with unchanged access/share_access
760 io
.ntcreatex
.in
.fname
= sname1
;
761 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
762 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
763 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
765 io
.ntcreatex
.in
.fname
= sname1b
;
766 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
767 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
769 io
.ntcreatex
.in
.fname
= sname1c
;
770 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
771 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
772 /* w2k returns INVALID_PARAMETER */
773 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
775 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
778 io
.ntcreatex
.in
.fname
= sname1d
;
779 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
780 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
781 /* w2k returns INVALID_PARAMETER */
782 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
784 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
787 io
.ntcreatex
.in
.fname
= sname2
;
788 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
789 CHECK_STATUS(status
, NT_STATUS_SHARING_VIOLATION
);
791 io
.ntcreatex
.in
.fname
= snamew
;
792 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
793 CHECK_STATUS(status
, NT_STATUS_OK
);
794 fnum3
= io
.ntcreatex
.out
.file
.fnum
;
796 io
.ntcreatex
.in
.fname
= snamew2
;
797 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
798 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
800 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
802 smbcli_close(cli
->tree
, fnum1
);
803 smbcli_close(cli
->tree
, fnum2
);
804 smbcli_close(cli
->tree
, fnum3
);
806 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
807 finfo
.generic
.in
.file
.path
= fname
;
808 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
809 CHECK_STATUS(status
, NT_STATUS_OK
);
811 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
813 for (i
=0; i
< 4; i
++) {
815 uint64_t stream_size
;
816 char *path
= talloc_asprintf(tctx
, "%s%s",
819 char *rpath
= talloc_strdup(path
, path
);
820 char *p
= strrchr(rpath
, ':');
828 printf("(%s): i[%u][%s]\n", __location__
, i
, path
);
829 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
830 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
831 SEC_FILE_WRITE_ATTRIBUTE
|
833 io
.ntcreatex
.in
.fname
= path
;
834 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
835 CHECK_STATUS(status
, NT_STATUS_OK
);
836 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
838 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
839 finfo
.generic
.in
.file
.path
= fname
;
840 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
841 CHECK_STATUS(status
, NT_STATUS_OK
);
843 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
844 stinfo
.generic
.in
.file
.fnum
= fnum1
;
845 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
846 CHECK_STATUS(status
, NT_STATUS_OK
);
847 if (!torture_setting_bool(tctx
, "samba3", false)) {
848 CHECK_NTTIME(stinfo
.all_info
.out
.create_time
,
849 finfo
.all_info
.out
.create_time
);
850 CHECK_NTTIME(stinfo
.all_info
.out
.access_time
,
851 finfo
.all_info
.out
.access_time
);
852 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
853 finfo
.all_info
.out
.write_time
);
854 CHECK_NTTIME(stinfo
.all_info
.out
.change_time
,
855 finfo
.all_info
.out
.change_time
);
857 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
858 finfo
.all_info
.out
.attrib
);
859 CHECK_VALUE(stinfo
.all_info
.out
.size
,
860 finfo
.all_info
.out
.size
);
861 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
862 finfo
.all_info
.out
.delete_pending
);
863 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
864 finfo
.all_info
.out
.directory
);
865 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
866 finfo
.all_info
.out
.ea_size
);
868 stinfo
.generic
.level
= RAW_FILEINFO_NAME_INFO
;
869 stinfo
.generic
.in
.file
.fnum
= fnum1
;
870 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
871 CHECK_STATUS(status
, NT_STATUS_OK
);
872 if (!torture_setting_bool(tctx
, "samba3", false)) {
873 CHECK_STR(stinfo
.name_info
.out
.fname
.s
, rpath
);
876 write_time
= finfo
.all_info
.out
.write_time
;
877 write_time
+= i
*1000000;
878 write_time
/= 1000000;
879 write_time
*= 1000000;
882 sinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
883 sinfo
.basic_info
.in
.file
.fnum
= fnum1
;
884 sinfo
.basic_info
.in
.write_time
= write_time
;
885 sinfo
.basic_info
.in
.attrib
= stinfo
.all_info
.out
.attrib
;
886 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
887 CHECK_STATUS(status
, NT_STATUS_OK
);
889 stream_size
= i
*8192;
892 sinfo
.end_of_file_info
.level
= RAW_SFILEINFO_END_OF_FILE_INFO
;
893 sinfo
.end_of_file_info
.in
.file
.fnum
= fnum1
;
894 sinfo
.end_of_file_info
.in
.size
= stream_size
;
895 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
896 CHECK_STATUS(status
, NT_STATUS_OK
);
898 stinfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
899 stinfo
.generic
.in
.file
.fnum
= fnum1
;
900 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &stinfo
);
901 CHECK_STATUS(status
, NT_STATUS_OK
);
902 if (!torture_setting_bool(tctx
, "samba3", false)) {
903 CHECK_NTTIME(stinfo
.all_info
.out
.write_time
,
905 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
906 finfo
.all_info
.out
.attrib
);
908 CHECK_VALUE(stinfo
.all_info
.out
.size
,
910 CHECK_VALUE(stinfo
.all_info
.out
.delete_pending
,
911 finfo
.all_info
.out
.delete_pending
);
912 CHECK_VALUE(stinfo
.all_info
.out
.directory
,
913 finfo
.all_info
.out
.directory
);
914 CHECK_VALUE(stinfo
.all_info
.out
.ea_size
,
915 finfo
.all_info
.out
.ea_size
);
917 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
919 smbcli_close(cli
->tree
, fnum1
);
923 printf("(%s): testing stream renames\n", __location__
);
924 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
925 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
926 SEC_FILE_WRITE_ATTRIBUTE
|
928 io
.ntcreatex
.in
.fname
= snamer1
;
929 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
930 CHECK_STATUS(status
, NT_STATUS_OK
);
931 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
933 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five1
);
936 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
937 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
938 sinfo
.rename_information
.in
.overwrite
= true;
939 sinfo
.rename_information
.in
.root_fid
= 0;
940 sinfo
.rename_information
.in
.new_name
= ":AfterRename:$DATA";
941 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
942 CHECK_STATUS(status
, NT_STATUS_OK
);
944 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
947 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
948 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
949 sinfo
.rename_information
.in
.overwrite
= false;
950 sinfo
.rename_information
.in
.root_fid
= 0;
951 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
952 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
953 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
955 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
958 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
959 sinfo
.rename_information
.in
.file
.fnum
= fnum1
;
960 sinfo
.rename_information
.in
.overwrite
= true;
961 sinfo
.rename_information
.in
.root_fid
= 0;
962 sinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
963 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
964 if (torture_setting_bool(tctx
, "samba4", false) ||
965 torture_setting_bool(tctx
, "samba3", false)) {
966 /* why should this rename be considered invalid?? */
967 CHECK_STATUS(status
, NT_STATUS_OK
);
968 ret
&= check_stream_list(tctx
, cli
, fname
, 4, four
);
970 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
971 ret
&= check_stream_list(tctx
, cli
, fname
, 5, five2
);
975 /* TODO: we need to test more rename combinations */
978 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
979 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
980 if (fnum3
!= -1) smbcli_close(cli
->tree
, fnum3
);
981 status
= smbcli_unlink(cli
->tree
, fname
);
982 smbcli_deltree(cli
->tree
, BASEDIR
);
989 static bool test_stream_names2(struct torture_context
*tctx
,
990 struct smbcli_state
*cli
)
994 const char *fname
= BASEDIR
"\\stream_names2.txt";
999 if (!torture_setup_dir(cli
, BASEDIR
)) {
1003 printf("(%s) testing stream names\n", __location__
);
1004 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1005 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1006 io
.ntcreatex
.in
.flags
= 0;
1007 io
.ntcreatex
.in
.access_mask
= SEC_FILE_WRITE_DATA
;
1008 io
.ntcreatex
.in
.create_options
= 0;
1009 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1010 io
.ntcreatex
.in
.share_access
= 0;
1011 io
.ntcreatex
.in
.alloc_size
= 0;
1012 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1013 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1014 io
.ntcreatex
.in
.security_flags
= 0;
1015 io
.ntcreatex
.in
.fname
= fname
;
1016 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1017 CHECK_STATUS(status
, NT_STATUS_OK
);
1018 fnum1
= io
.ntcreatex
.out
.file
.fnum
;
1020 for (i
=0x01; i
< 0x7F; i
++) {
1021 char *path
= talloc_asprintf(tctx
, "%s:Stream%c0x%02X:$DATA",
1029 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1032 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1037 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1038 io
.ntcreatex
.in
.fname
= path
;
1039 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1040 if (!NT_STATUS_EQUAL(status
, expected
)) {
1041 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1042 __location__
, fname
, isprint(i
)?(char)i
:' ', i
,
1043 isprint(i
)?"":" (not printable)",
1044 nt_errstr(expected
));
1046 CHECK_STATUS(status
, expected
);
1052 if (fnum1
!= -1) smbcli_close(cli
->tree
, fnum1
);
1053 status
= smbcli_unlink(cli
->tree
, fname
);
1054 smbcli_deltree(cli
->tree
, BASEDIR
);
1058 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1059 check_fnum = true; \
1060 call_name = #call; \
1061 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1062 sfinfo.generic.in.file.fnum = fnum; \
1063 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1064 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1065 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1066 nt_errstr(status), nt_errstr(rightstatus)); \
1069 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1070 finfo1.generic.in.file.fnum = fnum; \
1071 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1072 if (!NT_STATUS_IS_OK(status2)) { \
1073 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1080 static bool test_stream_rename(struct torture_context
*tctx
,
1081 struct smbcli_state
*cli
)
1083 NTSTATUS status
, status2
;
1085 const char *fname
= BASEDIR
"\\stream_rename.txt";
1086 const char *sname1
, *sname2
;
1087 union smb_fileinfo finfo1
;
1088 union smb_setfileinfo sfinfo
;
1092 const char *call_name
;
1094 if (!torture_setup_dir(cli
, BASEDIR
)) {
1098 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "Stream One");
1099 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1101 printf("(%s) testing stream renames\n", __location__
);
1102 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1103 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1104 io
.ntcreatex
.in
.flags
= 0;
1105 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1106 SEC_FILE_WRITE_ATTRIBUTE
|
1107 SEC_RIGHTS_FILE_ALL
;
1108 io
.ntcreatex
.in
.create_options
= 0;
1109 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1110 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1111 io
.ntcreatex
.in
.alloc_size
= 0;
1112 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1113 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1114 io
.ntcreatex
.in
.security_flags
= 0;
1115 io
.ntcreatex
.in
.fname
= sname1
;
1117 /* Create two streams. */
1118 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1119 CHECK_STATUS(status
, NT_STATUS_OK
);
1120 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1121 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1123 io
.ntcreatex
.in
.fname
= sname2
;
1124 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1125 CHECK_STATUS(status
, NT_STATUS_OK
);
1126 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1128 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1131 * Open the second stream.
1134 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1135 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1136 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1137 CHECK_STATUS(status
, NT_STATUS_OK
);
1138 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1141 * Now rename the second stream onto the first.
1144 ZERO_STRUCT(sfinfo
);
1146 sfinfo
.rename_information
.in
.overwrite
= 1;
1147 sfinfo
.rename_information
.in
.root_fid
= 0;
1148 sfinfo
.rename_information
.in
.new_name
= ":Stream One";
1149 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1152 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1153 status
= smbcli_unlink(cli
->tree
, fname
);
1154 smbcli_deltree(cli
->tree
, BASEDIR
);
1158 static bool test_stream_rename2(struct torture_context
*tctx
,
1159 struct smbcli_state
*cli
)
1163 const char *fname1
= BASEDIR
"\\stream.txt";
1164 const char *fname2
= BASEDIR
"\\stream2.txt";
1165 const char *stream_name1
= ":Stream One:$DATA";
1166 const char *stream_name2
= ":Stream Two:$DATA";
1167 const char *stream_name_default
= "::$DATA";
1172 union smb_setfileinfo sinfo
;
1173 union smb_rename rio
;
1175 if (!torture_setup_dir(cli
, BASEDIR
)) {
1179 sname1
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream One");
1180 sname2
= talloc_asprintf(tctx
, "%s:%s", fname1
, "Stream Two");
1182 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1183 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1184 io
.ntcreatex
.in
.flags
= 0;
1185 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1186 SEC_STD_DELETE
|SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1187 io
.ntcreatex
.in
.create_options
= 0;
1188 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1189 io
.ntcreatex
.in
.share_access
= (NTCREATEX_SHARE_ACCESS_READ
|
1190 NTCREATEX_SHARE_ACCESS_WRITE
|
1191 NTCREATEX_SHARE_ACCESS_DELETE
);
1192 io
.ntcreatex
.in
.alloc_size
= 0;
1193 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1194 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1195 io
.ntcreatex
.in
.security_flags
= 0;
1196 io
.ntcreatex
.in
.fname
= sname1
;
1198 /* Open/create new stream. */
1199 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1200 CHECK_STATUS(status
, NT_STATUS_OK
);
1202 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1205 * Check raw rename with <base>:<stream>.
1207 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1209 rio
.generic
.level
= RAW_RENAME_NTRENAME
;
1210 rio
.ntrename
.in
.old_name
= sname1
;
1211 rio
.ntrename
.in
.new_name
= sname2
;
1212 rio
.ntrename
.in
.attrib
= 0;
1213 rio
.ntrename
.in
.cluster_size
= 0;
1214 rio
.ntrename
.in
.flags
= RENAME_FLAG_RENAME
;
1215 status
= smb_raw_rename(cli
->tree
, &rio
);
1216 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1219 * Check raw rename to the default stream using :<stream>.
1221 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1223 rio
.ntrename
.in
.new_name
= stream_name_default
;
1224 status
= smb_raw_rename(cli
->tree
, &rio
);
1225 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_COLLISION
);
1228 * Check raw rename using :<stream>.
1230 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1232 rio
.ntrename
.in
.new_name
= stream_name2
;
1233 status
= smb_raw_rename(cli
->tree
, &rio
);
1234 CHECK_STATUS(status
, NT_STATUS_OK
);
1237 * Check raw rename of a stream to a file.
1239 printf("(%s) Checking NTRENAME of a stream to a file\n",
1241 rio
.ntrename
.in
.old_name
= sname2
;
1242 rio
.ntrename
.in
.new_name
= fname2
;
1243 status
= smb_raw_rename(cli
->tree
, &rio
);
1244 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1247 * Check raw rename of a file to a stream.
1249 printf("(%s) Checking NTRENAME of a file to a stream\n",
1252 /* Create the file. */
1253 io
.ntcreatex
.in
.fname
= fname2
;
1254 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1255 CHECK_STATUS(status
, NT_STATUS_OK
);
1256 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1258 /* Try the rename. */
1259 rio
.ntrename
.in
.old_name
= fname2
;
1260 rio
.ntrename
.in
.new_name
= sname1
;
1261 status
= smb_raw_rename(cli
->tree
, &rio
);
1262 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_INVALID
);
1265 * Reopen the stream for trans2 renames.
1267 io
.ntcreatex
.in
.fname
= sname2
;
1268 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1269 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1270 CHECK_STATUS(status
, NT_STATUS_OK
);
1271 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1274 * Check trans2 rename of a stream using :<stream>.
1276 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1279 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1280 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1281 sinfo
.rename_information
.in
.overwrite
= 1;
1282 sinfo
.rename_information
.in
.root_fid
= 0;
1283 sinfo
.rename_information
.in
.new_name
= stream_name1
;
1284 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1285 CHECK_STATUS(status
, NT_STATUS_OK
);
1288 * Check trans2 rename of an overwriting stream using :<stream>.
1290 printf("(%s) Checking trans2 rename of an overwriting stream using "
1291 ":<stream>\n", __location__
);
1293 /* Create second stream. */
1294 io
.ntcreatex
.in
.fname
= sname2
;
1295 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1296 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1297 CHECK_STATUS(status
, NT_STATUS_OK
);
1298 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1300 /* Rename the first stream onto the second. */
1301 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1302 sinfo
.rename_information
.in
.new_name
= stream_name2
;
1303 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1304 CHECK_STATUS(status
, NT_STATUS_OK
);
1306 smbcli_close(cli
->tree
, fnum
);
1309 * Reopen the stream with the new name.
1311 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1312 io
.ntcreatex
.in
.fname
= sname2
;
1313 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1314 CHECK_STATUS(status
, NT_STATUS_OK
);
1315 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1318 * Check trans2 rename of a stream using <base>:<stream>.
1320 printf("(%s) Checking trans2 rename of a stream using "
1321 "<base>:<stream>\n", __location__
);
1322 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1323 sinfo
.rename_information
.in
.new_name
= sname1
;
1324 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1325 CHECK_STATUS(status
, NT_STATUS_NOT_SUPPORTED
);
1328 * Samba3 doesn't currently support renaming a stream to the default
1329 * stream. This test does pass on windows.
1331 if (torture_setting_bool(tctx
, "samba3", false) ||
1332 torture_setting_bool(tctx
, "samba4", false)) {
1337 * Check trans2 rename to the default stream using :<stream>.
1339 printf("(%s) Checking trans2 rename to defaualt stream using "
1340 ":<stream>\n", __location__
);
1341 sinfo
.rename_information
.in
.file
.fnum
= fnum
;
1342 sinfo
.rename_information
.in
.new_name
= stream_name_default
;
1343 status
= smb_raw_setfileinfo(cli
->tree
, &sinfo
);
1344 CHECK_STATUS(status
, NT_STATUS_OK
);
1346 smbcli_close(cli
->tree
, fnum
);
1349 smbcli_close(cli
->tree
, fnum
);
1350 status
= smbcli_unlink(cli
->tree
, fname1
);
1351 status
= smbcli_unlink(cli
->tree
, fname2
);
1352 smbcli_deltree(cli
->tree
, BASEDIR
);
1359 static bool test_stream_rename3(struct torture_context
*tctx
,
1360 struct smbcli_state
*cli
)
1362 NTSTATUS status
, status2
;
1364 const char *fname
= BASEDIR
"\\stream_rename.txt";
1365 const char *sname1
, *sname2
;
1366 union smb_fileinfo finfo1
;
1367 union smb_setfileinfo sfinfo
;
1372 const char *call_name
;
1374 if (!torture_setup_dir(cli
, BASEDIR
)) {
1378 sname1
= talloc_asprintf(tctx
, "%s:%s", fname
, "MStream Two:$DATA");
1379 sname2
= talloc_asprintf(tctx
, "%s:%s:$DaTa", fname
, "Second Stream");
1381 printf("(%s) testing stream renames\n", __location__
);
1382 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1383 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1384 io
.ntcreatex
.in
.flags
= 0;
1385 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_ATTRIBUTE
|
1386 SEC_FILE_WRITE_ATTRIBUTE
|
1387 SEC_RIGHTS_FILE_ALL
;
1388 io
.ntcreatex
.in
.create_options
= 0;
1389 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1390 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1391 NTCREATEX_SHARE_ACCESS_WRITE
| NTCREATEX_SHARE_ACCESS_DELETE
;
1392 io
.ntcreatex
.in
.alloc_size
= 0;
1393 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1394 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1395 io
.ntcreatex
.in
.security_flags
= 0;
1396 io
.ntcreatex
.in
.fname
= sname1
;
1398 /* Create two streams. */
1399 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1400 CHECK_STATUS(status
, NT_STATUS_OK
);
1401 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1402 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1404 io
.ntcreatex
.in
.fname
= sname2
;
1405 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1406 CHECK_STATUS(status
, NT_STATUS_OK
);
1407 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1409 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1411 /* open the second stream. */
1412 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1413 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1414 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1415 CHECK_STATUS(status
, NT_STATUS_OK
);
1416 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1418 /* Keep a handle to the first stream open. */
1419 io
.ntcreatex
.in
.fname
= sname1
;
1420 io
.ntcreatex
.in
.access_mask
= SEC_STD_DELETE
;
1421 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1422 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1423 CHECK_STATUS(status
, NT_STATUS_OK
);
1424 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
1426 ZERO_STRUCT(sfinfo
);
1427 sfinfo
.rename_information
.in
.overwrite
= 1;
1428 sfinfo
.rename_information
.in
.root_fid
= 0;
1429 sfinfo
.rename_information
.in
.new_name
= ":MStream Two:$DATA";
1430 if (torture_setting_bool(tctx
, "samba4", false) ||
1431 torture_setting_bool(tctx
, "samba3", false)) {
1432 CHECK_CALL_FNUM(RENAME_INFORMATION
, NT_STATUS_OK
);
1434 CHECK_CALL_FNUM(RENAME_INFORMATION
,
1435 NT_STATUS_INVALID_PARAMETER
);
1440 if (fnum
!= -1) smbcli_close(cli
->tree
, fnum
);
1441 if (fnum2
!= -1) smbcli_close(cli
->tree
, fnum2
);
1442 status
= smbcli_unlink(cli
->tree
, fname
);
1443 smbcli_deltree(cli
->tree
, BASEDIR
);
1447 static bool create_file_with_stream(struct torture_context
*tctx
,
1448 struct smbcli_state
*cli
,
1455 /* Create a file with a stream */
1456 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1457 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1458 io
.ntcreatex
.in
.flags
= 0;
1459 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1460 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1461 io
.ntcreatex
.in
.create_options
= 0;
1462 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1463 io
.ntcreatex
.in
.share_access
= 0;
1464 io
.ntcreatex
.in
.alloc_size
= 0;
1465 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1466 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1467 io
.ntcreatex
.in
.security_flags
= 0;
1468 io
.ntcreatex
.in
.fname
= stream
;
1470 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1471 CHECK_STATUS(status
, NT_STATUS_OK
);
1474 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1478 /* Test how streams interact with create dispositions */
1479 static bool test_stream_create_disposition(struct torture_context
*tctx
,
1480 struct smbcli_state
*cli
)
1484 const char *fname
= BASEDIR
"\\stream.txt";
1485 const char *stream
= "Stream One:$DATA";
1486 const char *fname_stream
;
1487 const char *default_stream_name
= "::$DATA";
1488 const char *stream_list
[2];
1492 if (!torture_setup_dir(cli
, BASEDIR
)) {
1496 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1498 stream_list
[0] = talloc_asprintf(tctx
, ":%s", stream
);
1499 stream_list
[1] = default_stream_name
;
1501 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1505 /* Open the base file with OPEN */
1506 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1507 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1508 io
.ntcreatex
.in
.flags
= 0;
1509 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1510 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
);
1511 io
.ntcreatex
.in
.create_options
= 0;
1512 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1513 io
.ntcreatex
.in
.share_access
= 0;
1514 io
.ntcreatex
.in
.alloc_size
= 0;
1515 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1516 io
.ntcreatex
.in
.security_flags
= 0;
1517 io
.ntcreatex
.in
.fname
= fname
;
1520 * check ntcreatex open: sanity check
1522 printf("(%s) Checking ntcreatex disp: open\n", __location__
);
1523 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1524 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1525 CHECK_STATUS(status
, NT_STATUS_OK
);
1526 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1527 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1532 * check ntcreatex overwrite
1534 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__
);
1535 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
1536 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1537 CHECK_STATUS(status
, NT_STATUS_OK
);
1538 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1539 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1544 * check ntcreatex overwrite_if
1546 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__
);
1547 smbcli_unlink(cli
->tree
, fname
);
1548 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1552 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1553 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1554 CHECK_STATUS(status
, NT_STATUS_OK
);
1555 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1556 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1561 * check ntcreatex supersede
1563 printf("(%s) Checking ntcreatex disp: supersede\n", __location__
);
1564 smbcli_unlink(cli
->tree
, fname
);
1565 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1569 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_SUPERSEDE
;
1570 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1571 CHECK_STATUS(status
, NT_STATUS_OK
);
1572 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1573 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1578 * check ntcreatex overwrite_if on a stream.
1580 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1582 smbcli_unlink(cli
->tree
, fname
);
1583 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1587 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
1588 io
.ntcreatex
.in
.fname
= fname_stream
;
1589 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1590 CHECK_STATUS(status
, NT_STATUS_OK
);
1591 smbcli_close(cli
->tree
, io
.ntcreatex
.out
.file
.fnum
);
1592 if (!check_stream_list(tctx
, cli
, fname
, 2, stream_list
)) {
1597 * check openx overwrite_if
1599 printf("(%s) Checking openx disp: overwrite_if\n", __location__
);
1600 smbcli_unlink(cli
->tree
, fname
);
1601 if (!create_file_with_stream(tctx
, cli
, fname_stream
)) {
1605 io
.openx
.level
= RAW_OPEN_OPENX
;
1606 io
.openx
.in
.flags
= OPENX_FLAGS_ADDITIONAL_INFO
;
1607 io
.openx
.in
.open_mode
= OPENX_MODE_ACCESS_RDWR
| OPEN_FLAGS_DENY_NONE
;
1608 io
.openx
.in
.search_attrs
= 0;
1609 io
.openx
.in
.file_attrs
= 0;
1610 io
.openx
.in
.write_time
= 0;
1611 io
.openx
.in
.size
= 1024*1024;
1612 io
.openx
.in
.timeout
= 0;
1613 io
.openx
.in
.fname
= fname
;
1615 io
.openx
.in
.open_func
= OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
;
1616 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1617 CHECK_STATUS(status
, NT_STATUS_OK
);
1618 smbcli_close(cli
->tree
, io
.openx
.out
.file
.fnum
);
1619 if (!check_stream_list(tctx
, cli
, fname
, 1, &default_stream_name
)) {
1626 smbcli_close(cli
->tree
, fnum
);
1627 smbcli_unlink(cli
->tree
, fname
);
1628 smbcli_deltree(cli
->tree
, BASEDIR
);
1633 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1634 static bool test_stream_large_streaminfo(struct torture_context
*tctx
,
1635 struct smbcli_state
*cli
)
1637 #define LONG_STREAM_SIZE 2
1639 const char *fname
= BASEDIR
"\\stream.txt";
1640 const char *fname_stream
;
1644 union smb_fileinfo finfo
;
1646 if (!torture_setup_dir(cli
, BASEDIR
)) {
1650 lstream_name
= talloc_array(tctx
, char, LONG_STREAM_SIZE
);
1652 for (i
= 0; i
< LONG_STREAM_SIZE
- 1; i
++) {
1653 lstream_name
[i
] = (char)('a' + i
%26);
1655 lstream_name
[LONG_STREAM_SIZE
- 1] = '\0';
1657 torture_comment(tctx
, "(%s) Creating a file with a lot of streams\n", __location__
);
1658 for (i
= 0; i
< 10000; i
++) {
1659 fname_stream
= talloc_asprintf(tctx
, "%s:%s%d", fname
,
1661 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1667 finfo
.generic
.level
= RAW_FILEINFO_STREAM_INFO
;
1668 finfo
.generic
.in
.file
.path
= fname
;
1670 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1671 CHECK_STATUS(status
, STATUS_BUFFER_OVERFLOW
);
1674 smbcli_unlink(cli
->tree
, fname
);
1675 smbcli_deltree(cli
->tree
, BASEDIR
);
1680 /* Test the effect of setting attributes on a stream. */
1681 static bool test_stream_attributes(struct torture_context
*tctx
,
1682 struct smbcli_state
*cli
)
1687 const char *fname
= BASEDIR
"\\stream_attr.txt";
1688 const char *stream
= "Stream One:$DATA";
1689 const char *fname_stream
;
1691 union smb_fileinfo finfo
;
1692 union smb_setfileinfo sfinfo
;
1693 time_t basetime
= (time(NULL
) - 86400) & ~1;
1695 if (!torture_setup_dir(cli
, BASEDIR
)) {
1699 torture_comment(tctx
, "(%s) testing attribute setting on stream\n", __location__
);
1701 fname_stream
= talloc_asprintf(tctx
, "%s:%s", fname
, stream
);
1703 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1704 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1710 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1711 finfo
.generic
.in
.file
.path
= fname
;
1712 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1713 CHECK_STATUS(status
, NT_STATUS_OK
);
1715 if (finfo
.basic_info
.out
.attrib
!= FILE_ATTRIBUTE_ARCHIVE
) {
1716 printf("(%s) Incorrect attrib %x - should be %x\n", \
1717 __location__
, (unsigned int)finfo
.basic_info
.out
.attrib
,
1718 (unsigned int)FILE_ATTRIBUTE_ARCHIVE
);
1723 /* Now open the stream name. */
1725 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1726 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1727 io
.ntcreatex
.in
.flags
= 0;
1728 io
.ntcreatex
.in
.access_mask
= (SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
|
1729 SEC_FILE_APPEND_DATA
|SEC_STD_READ_CONTROL
|SEC_FILE_WRITE_ATTRIBUTE
);
1730 io
.ntcreatex
.in
.create_options
= 0;
1731 io
.ntcreatex
.in
.file_attr
= 0;
1732 io
.ntcreatex
.in
.share_access
= 0;
1733 io
.ntcreatex
.in
.alloc_size
= 0;
1734 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1735 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1736 io
.ntcreatex
.in
.security_flags
= 0;
1737 io
.ntcreatex
.in
.fname
= fname_stream
;
1739 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1740 CHECK_STATUS(status
, NT_STATUS_OK
);
1742 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1744 /* Change the attributes + time on the stream fnum. */
1745 ZERO_STRUCT(sfinfo
);
1746 sfinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_READONLY
;
1747 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, basetime
);
1749 sfinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1750 sfinfo
.generic
.in
.file
.fnum
= fnum
;
1751 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
1752 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
1753 printf("(%s) %s - %s (should be %s)\n", __location__
, "SETATTR",
1754 nt_errstr(status
), nt_errstr(NT_STATUS_OK
));
1759 smbcli_close(cli
->tree
, fnum
);
1763 finfo
.generic
.level
= RAW_FILEINFO_ALL_INFO
;
1764 finfo
.generic
.in
.file
.path
= fname
;
1765 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1766 if (!NT_STATUS_IS_OK(status
)) {
1767 printf("(%s) %s pathinfo - %s\n", __location__
, "SETATTRE", nt_errstr(status
));
1772 if (finfo
.all_info
.out
.attrib
!= FILE_ATTRIBUTE_READONLY
) {
1773 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1775 (unsigned int)finfo
.all_info
.out
.attrib
,
1776 (unsigned int)FILE_ATTRIBUTE_READONLY
);
1781 if (nt_time_to_unix(finfo
.all_info
.out
.write_time
) != basetime
) {
1782 printf("(%s) time incorrect.\n",
1791 smbcli_close(cli
->tree
, fnum
);
1793 smbcli_unlink(cli
->tree
, fname
);
1794 smbcli_deltree(cli
->tree
, BASEDIR
);
1799 * A rough approximation of how a windows client creates the streams for use
1800 * in the summary tab.
1802 static bool test_stream_summary_tab(struct torture_context
*tctx
,
1803 struct smbcli_state
*cli
)
1808 const char *fname
= BASEDIR
"\\stream_summary.txt";
1809 const char *stream
= ":\005SummaryInformation:$DATA";
1810 const char *fname_stream
= NULL
;
1811 const char *tmp_stream
= ":Updt_\005SummaryInformation:$DATA";
1812 const char *fname_tmp_stream
= NULL
;
1814 union smb_fileinfo finfo
;
1815 union smb_rename rio
;
1818 if (!torture_setup_dir(cli
, BASEDIR
)) {
1822 fname_stream
= talloc_asprintf(tctx
, "%s%s", fname
, stream
);
1823 fname_tmp_stream
= talloc_asprintf(tctx
, "%s%s", fname
,
1826 /* Create summary info stream */
1827 ret
= create_file_with_stream(tctx
, cli
, fname_stream
);
1832 /* Create summary info tmp update stream */
1833 ret
= create_file_with_stream(tctx
, cli
, fname_tmp_stream
);
1838 /* Open tmp stream and write to it */
1839 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1840 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1841 io
.ntcreatex
.in
.flags
= 0;
1842 io
.ntcreatex
.in
.access_mask
= SEC_FILE_READ_DATA
|SEC_FILE_WRITE_DATA
;
1843 io
.ntcreatex
.in
.create_options
= 0;
1844 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1845 io
.ntcreatex
.in
.share_access
= 0;
1846 io
.ntcreatex
.in
.alloc_size
= 0;
1847 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1848 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1849 io
.ntcreatex
.in
.security_flags
= 0;
1850 io
.ntcreatex
.in
.fname
= fname_tmp_stream
;
1852 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1853 CHECK_STATUS(status
, NT_STATUS_OK
);
1854 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1856 retsize
= smbcli_write(cli
->tree
, fnum
, 0, "test data", 0, 9);
1857 CHECK_VALUE(retsize
, 9);
1859 /* close the tmp stream. */
1860 smbcli_close(cli
->tree
, fnum
);
1863 /* Delete the current stream */
1864 smbcli_unlink(cli
->tree
, fname_stream
);
1866 /* Do the rename. */
1867 rio
.generic
.level
= RAW_RENAME_RENAME
;
1868 rio
.rename
.in
.pattern1
= fname_tmp_stream
;
1869 rio
.rename
.in
.pattern2
= stream
;
1870 rio
.rename
.in
.attrib
= FILE_ATTRIBUTE_SYSTEM
|
1871 FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
;
1872 status
= smb_raw_rename(cli
->tree
, &rio
);
1873 CHECK_STATUS(status
, NT_STATUS_OK
);
1875 /* Try to open the tmp stream that we just renamed away. */
1876 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1877 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1879 /* Query the base file to make sure it's still there. */
1880 finfo
.generic
.level
= RAW_FILEINFO_BASIC_INFO
;
1881 finfo
.generic
.in
.file
.path
= fname
;
1883 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo
);
1884 CHECK_STATUS(status
, NT_STATUS_OK
);
1889 smbcli_close(cli
->tree
, fnum
);
1891 smbcli_unlink(cli
->tree
, fname
);
1893 smbcli_deltree(cli
->tree
, BASEDIR
);
1898 basic testing of streams calls
1900 struct torture_suite
*torture_raw_streams(TALLOC_CTX
*tctx
)
1902 struct torture_suite
*suite
= torture_suite_create(tctx
, "streams");
1904 torture_suite_add_1smb_test(suite
, "dir", test_stream_dir
);
1905 torture_suite_add_1smb_test(suite
, "io", test_stream_io
);
1906 torture_suite_add_1smb_test(suite
, "sharemodes", test_stream_sharemodes
);
1907 torture_suite_add_1smb_test(suite
, "delete", test_stream_delete
);
1908 torture_suite_add_1smb_test(suite
, "names", test_stream_names
);
1909 torture_suite_add_1smb_test(suite
, "names2", test_stream_names2
);
1910 torture_suite_add_1smb_test(suite
, "rename", test_stream_rename
);
1911 torture_suite_add_1smb_test(suite
, "rename2", test_stream_rename2
);
1912 torture_suite_add_1smb_test(suite
, "rename3", test_stream_rename3
);
1913 torture_suite_add_1smb_test(suite
, "createdisp",
1914 test_stream_create_disposition
);
1915 torture_suite_add_1smb_test(suite
, "attr", test_stream_attributes
);
1916 torture_suite_add_1smb_test(suite
, "sumtab", test_stream_summary_tab
);
1919 torture_suite_add_1smb_test(suite
, "LARGESTREAMINFO",
1920 test_stream_large_streaminfo
);