root/source4/torture/raw/streams.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_stream
  2. qsort_string
  3. qsort_stream
  4. check_stream_list
  5. test_stream_dir
  6. test_stream_io
  7. test_stream_sharemodes
  8. test_stream_delete
  9. test_stream_names
  10. test_stream_names2
  11. test_stream_rename
  12. test_stream_rename2
  13. create_file_with_stream
  14. test_stream_create_disposition
  15. test_stream_large_streaminfo
  16. test_stream_attributes
  17. torture_raw_streams

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    test alternate data streams
   5 
   6    Copyright (C) Andrew Tridgell 2004
   7    
   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.
  12    
  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.
  17    
  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/>.
  20 */
  21 
  22 #include "includes.h"
  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 
  30 #define BASEDIR "\\teststreams"
  31 
  32 #define CHECK_STATUS(status, correct) do { \
  33         if (!NT_STATUS_EQUAL(status, correct)) { \
  34                 printf("(%s) Incorrect status %s - should be %s\n", \
  35                        __location__, nt_errstr(status), nt_errstr(correct)); \
  36                 ret = false; \
  37                 goto done; \
  38         }} while (0)
  39 
  40 #define CHECK_VALUE(v, correct) do { \
  41         if ((v) != (correct)) { \
  42                 printf("(%s) Incorrect value %s=%d - should be %d\n", \
  43                        __location__, #v, (int)v, (int)correct); \
  44                 ret = false; \
  45         }} while (0)
  46 
  47 #define CHECK_NTTIME(v, correct) do { \
  48         if ((v) != (correct)) { \
  49                 printf("(%s) Incorrect value %s=%llu - should be %llu\n", \
  50                        __location__, #v, (unsigned long long)v, \
  51                        (unsigned long long)correct); \
  52                 ret = false; \
  53         }} while (0)
  54 
  55 #define CHECK_STR(v, correct) do { \
  56         bool ok; \
  57         if ((v) && !(correct)) { \
  58                 ok = false; \
  59         } else if (!(v) && (correct)) { \
  60                 ok = false; \
  61         } else if (!(v) && !(correct)) { \
  62                 ok = true; \
  63         } else if (strcmp((v), (correct)) == 0) { \
  64                 ok = true; \
  65         } else { \
  66                 ok = false; \
  67         } \
  68         if (!ok) { \
  69                 printf("(%s) Incorrect value %s='%s' - should be '%s'\n", \
  70                        __location__, #v, (v)?(v):"NULL", \
  71                        (correct)?(correct):"NULL"); \
  72                 ret = false; \
  73         }} while (0)
  74 
  75 /*
  76   check that a stream has the right contents
  77 */
  78 static bool check_stream(struct smbcli_state *cli, const char *location,
     /* [<][>][^][v][top][bottom][index][help] */
  79                          TALLOC_CTX *mem_ctx,
  80                          const char *fname, const char *sname, 
  81                          const char *value)
  82 {
  83         int fnum;
  84         const char *full_name;
  85         uint8_t *buf;
  86         ssize_t ret;
  87 
  88         full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
  89 
  90         fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
  91 
  92         if (value == NULL) {
  93                 if (fnum != -1) {
  94                         printf("(%s) should have failed stream open of %s\n",
  95                                location, full_name);
  96                         return false;
  97                 }
  98                 return true;
  99         }
 100             
 101         if (fnum == -1) {
 102                 printf("(%s) Failed to open stream '%s' - %s\n",
 103                        location, full_name, smbcli_errstr(cli->tree));
 104                 return false;
 105         }
 106 
 107         buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
 108         
 109         ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
 110         if (ret != strlen(value)) {
 111                 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
 112                        location, (long)strlen(value), full_name, (int)ret);
 113                 return false;
 114         }
 115 
 116         if (memcmp(buf, value, strlen(value)) != 0) {
 117                 printf("(%s) Bad data in stream\n", location);
 118                 return false;
 119         }
 120 
 121         smbcli_close(cli->tree, fnum);
 122         return true;
 123 }
 124 
 125 static int qsort_string(const void *v1, const void *v2)
     /* [<][>][^][v][top][bottom][index][help] */
 126 {
 127         char * const *s1 = v1;
 128         char * const *s2 = v2;
 129         return strcmp(*s1, *s2);
 130 }
 131 
 132 static int qsort_stream(const void *v1, const void *v2)
     /* [<][>][^][v][top][bottom][index][help] */
 133 {
 134         const struct stream_struct * s1 = v1;
 135         const struct stream_struct * s2 = v2;
 136         return strcmp(s1->stream_name.s, s2->stream_name.s);
 137 }
 138 
 139 static bool check_stream_list(struct smbcli_state *cli, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 140                               int num_exp, const char **exp)
 141 {
 142         union smb_fileinfo finfo;
 143         NTSTATUS status;
 144         int i;
 145         TALLOC_CTX *tmp_ctx = talloc_new(cli);
 146         char **exp_sort;
 147         struct stream_struct *stream_sort;
 148         bool ret = false;
 149 
 150         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
 151         finfo.generic.in.file.path = fname;
 152 
 153         status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
 154         if (!NT_STATUS_IS_OK(status)) {
 155                 d_fprintf(stderr, "(%s) smb_raw_pathinfo failed: %s\n",
 156                           __location__, nt_errstr(status));
 157                 goto fail;
 158         }
 159 
 160         if (finfo.stream_info.out.num_streams != num_exp) {
 161                 d_fprintf(stderr, "(%s) expected %d streams, got %d\n",
 162                           __location__, num_exp,
 163                           finfo.stream_info.out.num_streams);
 164                 goto fail;
 165         }
 166 
 167         if (num_exp == 0) {
 168                 ret = true;
 169                 goto fail;
 170         }
 171 
 172         exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
 173 
 174         if (exp_sort == NULL) {
 175                 goto fail;
 176         }
 177 
 178         qsort(exp_sort, num_exp, sizeof(*exp_sort), qsort_string);
 179 
 180         stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
 181                                     finfo.stream_info.out.num_streams *
 182                                     sizeof(*stream_sort));
 183 
 184         if (stream_sort == NULL) {
 185                 goto fail;
 186         }
 187 
 188         qsort(stream_sort, finfo.stream_info.out.num_streams,
 189               sizeof(*stream_sort), qsort_stream);
 190 
 191         for (i=0; i<num_exp; i++) {
 192                 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
 193                         d_fprintf(stderr, "(%s) expected stream name %s, got "
 194                                   "%s\n", __location__, exp_sort[i],
 195                                   stream_sort[i].stream_name.s);
 196                         goto fail;
 197                 }
 198         }
 199 
 200         ret = true;
 201  fail:
 202         talloc_free(tmp_ctx);
 203         return ret;
 204 }
 205 
 206 /*
 207   test bahavior of streams on directories
 208 */
 209 static bool test_stream_dir(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 210                            struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 211 {
 212         NTSTATUS status;
 213         union smb_open io;
 214         const char *fname = BASEDIR "\\stream.txt";
 215         const char *sname1;
 216         bool ret = true;
 217         const char *basedir_data;
 218 
 219         basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", BASEDIR);
 220         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
 221 
 222         printf("(%s) opening non-existant directory stream\n", __location__);
 223         io.generic.level = RAW_OPEN_NTCREATEX;
 224         io.ntcreatex.in.root_fid = 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_NORMAL;
 229         io.ntcreatex.in.share_access = 0;
 230         io.ntcreatex.in.alloc_size = 0;
 231         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 232         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 233         io.ntcreatex.in.security_flags = 0;
 234         io.ntcreatex.in.fname = sname1;
 235         status = smb_raw_open(cli->tree, mem_ctx, &io);
 236         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
 237 
 238         printf("(%s) opening basedir  stream\n", __location__);
 239         io.generic.level = RAW_OPEN_NTCREATEX;
 240         io.ntcreatex.in.root_fid = 0;
 241         io.ntcreatex.in.flags = 0;
 242         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
 243         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
 244         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
 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, mem_ctx, &io);
 252         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
 253 
 254         printf("(%s) opening basedir ::$DATA stream\n", __location__);
 255         io.generic.level = RAW_OPEN_NTCREATEX;
 256         io.ntcreatex.in.root_fid = 0;
 257         io.ntcreatex.in.flags = 0x10;
 258         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
 259         io.ntcreatex.in.create_options = 0;
 260         io.ntcreatex.in.file_attr = 0;
 261         io.ntcreatex.in.share_access = 0;
 262         io.ntcreatex.in.alloc_size = 0;
 263         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 264         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 265         io.ntcreatex.in.security_flags = 0;
 266         io.ntcreatex.in.fname = basedir_data;
 267         status = smb_raw_open(cli->tree, mem_ctx, &io);
 268         CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
 269 
 270         printf("(%s) list the streams on the basedir\n", __location__);
 271         ret &= check_stream_list(cli, BASEDIR, 0, NULL);
 272 done:
 273         return ret;
 274 }
 275 
 276 /*
 277   test basic behavior of streams on directories
 278 */
 279 static bool test_stream_io(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 280                            struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 281 {
 282         NTSTATUS status;
 283         union smb_open io;
 284         const char *fname = BASEDIR "\\stream.txt";
 285         const char *sname1, *sname2;
 286         bool ret = true;
 287         int fnum = -1;
 288         ssize_t retsize;
 289 
 290         const char *one[] = { "::$DATA" };
 291         const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
 292         const char *three[] = { "::$DATA", ":Stream One:$DATA",
 293                                 ":Second Stream:$DATA" };
 294 
 295         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
 296         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
 297 
 298         printf("(%s) creating a stream on a non-existant file\n", __location__);
 299         io.generic.level = RAW_OPEN_NTCREATEX;
 300         io.ntcreatex.in.root_fid = 0;
 301         io.ntcreatex.in.flags = 0;
 302         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
 303         io.ntcreatex.in.create_options = 0;
 304         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
 305         io.ntcreatex.in.share_access = 0;
 306         io.ntcreatex.in.alloc_size = 0;
 307         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 308         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 309         io.ntcreatex.in.security_flags = 0;
 310         io.ntcreatex.in.fname = sname1;
 311         status = smb_raw_open(cli->tree, mem_ctx, &io);
 312         CHECK_STATUS(status, NT_STATUS_OK);
 313         fnum = io.ntcreatex.out.file.fnum;
 314 
 315         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One", NULL);
 316 
 317         printf("(%s) check that open of base file is allowed\n", __location__);
 318         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 319         io.ntcreatex.in.fname = fname;
 320         status = smb_raw_open(cli->tree, mem_ctx, &io);
 321         CHECK_STATUS(status, NT_STATUS_OK);
 322         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
 323 
 324         printf("(%s) writing to stream\n", __location__);
 325         retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
 326         CHECK_VALUE(retsize, 9);
 327 
 328         smbcli_close(cli->tree, fnum);
 329 
 330         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One", "test data");
 331 
 332         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 333         io.ntcreatex.in.fname = sname1;
 334         status = smb_raw_open(cli->tree, mem_ctx, &io);
 335         CHECK_STATUS(status, NT_STATUS_OK);
 336         fnum = io.ntcreatex.out.file.fnum;
 337 
 338         printf("(%s) modifying stream\n", __location__);
 339         retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
 340         CHECK_VALUE(retsize, 10);
 341 
 342         smbcli_close(cli->tree, fnum);
 343 
 344         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One:$FOO", NULL);
 345 
 346         printf("(%s) creating a stream2 on a existing file\n", __location__);
 347         io.ntcreatex.in.fname = sname2;
 348         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
 349         status = smb_raw_open(cli->tree, mem_ctx, &io);
 350         CHECK_STATUS(status, NT_STATUS_OK);
 351         fnum = io.ntcreatex.out.file.fnum;
 352 
 353         printf("(%s) modifying stream\n", __location__);
 354         retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
 355         CHECK_VALUE(retsize, 13);
 356 
 357         smbcli_close(cli->tree, fnum);
 358 
 359         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One", "test MORE DATA ");
 360         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One:$DATA", "test MORE DATA ");
 361         ret &= check_stream(cli, __location__, mem_ctx, fname, "Stream One:", NULL);
 362         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream", "SECOND STREAM");
 363         if (!torture_setting_bool(tctx, "samba4", false)) {
 364                 ret &= check_stream(cli, __location__, mem_ctx, fname,
 365                                     "SECOND STREAM:$DATA", "SECOND STREAM");
 366         }
 367         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream:$DATA", "SECOND STREAM");
 368         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream:", NULL);
 369         ret &= check_stream(cli, __location__, mem_ctx, fname, "Second Stream:$FOO", NULL);
 370 
 371         check_stream_list(cli, fname, 3, three);
 372 
 373         printf("(%s) deleting stream\n", __location__);
 374         status = smbcli_unlink(cli->tree, sname1);
 375         CHECK_STATUS(status, NT_STATUS_OK);
 376 
 377         check_stream_list(cli, fname, 2, two);
 378 
 379         printf("(%s) delete a stream via delete-on-close\n", __location__);
 380         io.ntcreatex.in.fname = sname2;
 381         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
 382         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
 383         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
 384         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 385 
 386         status = smb_raw_open(cli->tree, mem_ctx, &io);
 387         CHECK_STATUS(status, NT_STATUS_OK);
 388         fnum = io.ntcreatex.out.file.fnum;
 389         
 390         smbcli_close(cli->tree, fnum);
 391         status = smbcli_unlink(cli->tree, sname2);
 392         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
 393 
 394         check_stream_list(cli, fname, 1, one);
 395 
 396         if (!torture_setting_bool(tctx, "samba4", false)) {
 397                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 398                 io.ntcreatex.in.fname = sname1;
 399                 status = smb_raw_open(cli->tree, mem_ctx, &io);
 400                 CHECK_STATUS(status, NT_STATUS_OK);
 401                 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
 402                 io.ntcreatex.in.fname = sname2;
 403                 status = smb_raw_open(cli->tree, mem_ctx, &io);
 404                 CHECK_STATUS(status, NT_STATUS_OK);
 405                 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
 406         }
 407 
 408         printf("(%s) deleting file\n", __location__);
 409         status = smbcli_unlink(cli->tree, fname);
 410         CHECK_STATUS(status, NT_STATUS_OK);
 411 
 412 done:
 413         smbcli_close(cli->tree, fnum);
 414         return ret;
 415 }
 416 
 417 /*
 418   test stream sharemodes
 419 */
 420 static bool test_stream_sharemodes(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 421                                    struct smbcli_state *cli,
 422                                    TALLOC_CTX *mem_ctx)
 423 {
 424         NTSTATUS status;
 425         union smb_open io;
 426         const char *fname = BASEDIR "\\stream.txt";
 427         const char *sname1, *sname2;
 428         bool ret = true;
 429         int fnum1 = -1;
 430         int fnum2 = -1;
 431 
 432         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
 433         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
 434 
 435         printf("(%s) testing stream share mode conflicts\n", __location__);
 436         io.generic.level = RAW_OPEN_NTCREATEX;
 437         io.ntcreatex.in.root_fid = 0;
 438         io.ntcreatex.in.flags = 0;
 439         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
 440         io.ntcreatex.in.create_options = 0;
 441         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
 442         io.ntcreatex.in.share_access = 0;
 443         io.ntcreatex.in.alloc_size = 0;
 444         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 445         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 446         io.ntcreatex.in.security_flags = 0;
 447         io.ntcreatex.in.fname = sname1;
 448 
 449         status = smb_raw_open(cli->tree, mem_ctx, &io);
 450         CHECK_STATUS(status, NT_STATUS_OK);
 451         fnum1 = io.ntcreatex.out.file.fnum;
 452 
 453         /*
 454          * A different stream does not give a sharing violation
 455          */
 456 
 457         io.ntcreatex.in.fname = sname2;
 458         status = smb_raw_open(cli->tree, mem_ctx, &io);
 459         CHECK_STATUS(status, NT_STATUS_OK);
 460         fnum2 = io.ntcreatex.out.file.fnum;
 461 
 462         /*
 463          * ... whereas the same stream does with unchanged access/share_access
 464          * flags
 465          */
 466 
 467         io.ntcreatex.in.fname = sname1;
 468         io.ntcreatex.in.open_disposition = 0;
 469         status = smb_raw_open(cli->tree, mem_ctx, &io);
 470         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 471 
 472         io.ntcreatex.in.fname = sname2;
 473         status = smb_raw_open(cli->tree, mem_ctx, &io);
 474         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 475 
 476 done:
 477         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
 478         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
 479         status = smbcli_unlink(cli->tree, fname);
 480         return ret;
 481 }
 482 
 483 /* 
 484  *  Test FILE_SHARE_DELETE on streams
 485  *
 486  * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
 487  * with SEC_STD_DELETE.
 488  *
 489  * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
 490  * be opened with SEC_STD_DELETE.
 491  *
 492  * A stream held open with FILE_SHARE_DELETE allows the file to be
 493  * deleted. After the main file is deleted, access to the open file descriptor
 494  * still works, but all name-based access to both the main file as well as the
 495  * stream is denied with DELETE ending.
 496  *
 497  * This means, an open of the main file with SEC_STD_DELETE should walk all
 498  * streams and also open them with SEC_STD_DELETE. If any of these opens gives
 499  * SHARING_VIOLATION, the main open fails.
 500  *
 501  * Closing the main file after delete_on_close has been set does not really
 502  * unlink it but leaves the corresponding share mode entry with
 503  * delete_on_close being set around until all streams are closed.
 504  *
 505  * Opening a stream must also look at the main file's share mode entry, look
 506  * at the delete_on_close bit and potentially return DELETE_PENDING.
 507  */
 508 
 509 static bool test_stream_delete(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 510                                struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 511 {
 512         NTSTATUS status;
 513         union smb_open io;
 514         const char *fname = BASEDIR "\\stream.txt";
 515         const char *sname1;
 516         bool ret = true;
 517         int fnum = -1;
 518         uint8_t buf[9];
 519         ssize_t retsize;
 520         union smb_fileinfo finfo;
 521 
 522         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
 523 
 524         printf("(%s) opening non-existant file stream\n", __location__);
 525         io.generic.level = RAW_OPEN_NTCREATEX;
 526         io.ntcreatex.in.root_fid = 0;
 527         io.ntcreatex.in.flags = 0;
 528         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
 529         io.ntcreatex.in.create_options = 0;
 530         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
 531         io.ntcreatex.in.share_access = 0;
 532         io.ntcreatex.in.alloc_size = 0;
 533         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 534         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 535         io.ntcreatex.in.security_flags = 0;
 536         io.ntcreatex.in.fname = sname1;
 537 
 538         status = smb_raw_open(cli->tree, mem_ctx, &io);
 539         CHECK_STATUS(status, NT_STATUS_OK);
 540         fnum = io.ntcreatex.out.file.fnum;
 541 
 542         retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
 543         CHECK_VALUE(retsize, 9);
 544 
 545         /*
 546          * One stream opened without FILE_SHARE_DELETE prevents the main file
 547          * to be deleted or even opened with DELETE access
 548          */
 549 
 550         status = smbcli_unlink(cli->tree, fname);
 551         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 552 
 553         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 554         io.ntcreatex.in.fname = fname;
 555         io.ntcreatex.in.access_mask = SEC_STD_DELETE;
 556         status = smb_raw_open(cli->tree, mem_ctx, &io);
 557         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 558 
 559         smbcli_close(cli->tree, fnum);
 560 
 561         /*
 562          * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
 563          */
 564 
 565         io.ntcreatex.in.fname = sname1;
 566         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
 567         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
 568         status = smb_raw_open(cli->tree, mem_ctx, &io);
 569         CHECK_STATUS(status, NT_STATUS_OK);
 570         fnum = io.ntcreatex.out.file.fnum;
 571 
 572         status = smbcli_unlink(cli->tree, fname);
 573         CHECK_STATUS(status, NT_STATUS_OK);
 574 
 575         /*
 576          * file access still works on the stream while the main file is closed
 577          */
 578 
 579         retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
 580         CHECK_VALUE(retsize, 9);
 581 
 582         finfo.generic.level = RAW_FILEINFO_STANDARD;
 583         finfo.generic.in.file.path = fname;
 584 
 585         /*
 586          * name-based access to both the main file and the stream does not
 587          * work anymore but gives DELETE_PENDING
 588          */
 589 
 590         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
 591         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
 592 
 593         /*
 594          * older S3 doesn't do this
 595          */
 596         finfo.generic.in.file.path = sname1;
 597         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
 598         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
 599 
 600         /*
 601          * fd-based qfileinfo on the stream still works, the stream does not
 602          * have the delete-on-close bit set. This could mean that open on the
 603          * stream first opens the main file
 604          */
 605 
 606         finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
 607         finfo.all_info.in.file.fnum = fnum;
 608 
 609         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
 610         CHECK_STATUS(status, NT_STATUS_OK);
 611         /* w2k and w2k3 return 0 and w2k8 returns 1
 612         CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
 613         */
 614 
 615         smbcli_close(cli->tree, fnum);
 616 
 617         /*
 618          * After closing the stream the file is really gone.
 619          */
 620 
 621         finfo.generic.in.file.path = fname;
 622         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
 623         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
 624 
 625         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA
 626                 |SEC_STD_DELETE;
 627         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
 628         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 629         status = smb_raw_open(cli->tree, mem_ctx, &io);
 630         CHECK_STATUS(status, NT_STATUS_OK);
 631         fnum = io.ntcreatex.out.file.fnum;
 632 
 633         finfo.generic.in.file.path = fname;
 634         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
 635         CHECK_STATUS(status, NT_STATUS_OK);
 636 
 637         smbcli_close(cli->tree, fnum);
 638 
 639         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
 640         CHECK_STATUS(status, NT_STATUS_OK);
 641 done:
 642         smbcli_close(cli->tree, fnum);
 643         smbcli_unlink(cli->tree, fname);
 644         return ret;
 645 }
 646 
 647 /*
 648   test stream names
 649 */
 650 static bool test_stream_names(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 651                               struct smbcli_state *cli,
 652                               TALLOC_CTX *mem_ctx)
 653 {
 654         NTSTATUS status;
 655         union smb_open io;
 656         union smb_fileinfo finfo;
 657         union smb_fileinfo stinfo;
 658         union smb_setfileinfo sinfo;
 659         const char *fname = BASEDIR "\\stream_names.txt";
 660         const char *sname1, *sname1b, *sname1c, *sname1d;
 661         const char *sname2, *snamew, *snamew2;
 662         const char *snamer1, *snamer2;
 663         bool ret = true;
 664         int fnum1 = -1;
 665         int fnum2 = -1;
 666         int fnum3 = -1;
 667         int i;
 668         const char *four[4] = {
 669                 "::$DATA",
 670                 ":\x05Stream\n One:$DATA",
 671                 ":MStream Two:$DATA",
 672                 ":?Stream*:$DATA"
 673         };
 674         const char *five1[5] = {
 675                 "::$DATA",
 676                 ":\x05Stream\n One:$DATA",
 677                 ":BeforeRename:$DATA",
 678                 ":MStream Two:$DATA",
 679                 ":?Stream*:$DATA"
 680         };
 681         const char *five2[5] = {
 682                 "::$DATA",
 683                 ":\x05Stream\n One:$DATA",
 684                 ":AfterRename:$DATA",
 685                 ":MStream Two:$DATA",
 686                 ":?Stream*:$DATA"
 687         };
 688 
 689         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
 690         sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
 691         sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
 692         sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
 693         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
 694         snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
 695         snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
 696         snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "BeforeRename");
 697         snamer2 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "AfterRename");
 698 
 699         printf("(%s) testing stream names\n", __location__);
 700         io.generic.level = RAW_OPEN_NTCREATEX;
 701         io.ntcreatex.in.root_fid = 0;
 702         io.ntcreatex.in.flags = 0;
 703         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
 704         io.ntcreatex.in.create_options = 0;
 705         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
 706         io.ntcreatex.in.share_access = 0;
 707         io.ntcreatex.in.alloc_size = 0;
 708         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 709         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 710         io.ntcreatex.in.security_flags = 0;
 711         io.ntcreatex.in.fname = sname1;
 712 
 713         status = smb_raw_open(cli->tree, mem_ctx, &io);
 714         CHECK_STATUS(status, NT_STATUS_OK);
 715         fnum1 = io.ntcreatex.out.file.fnum;
 716 
 717         /*
 718          * A different stream does not give a sharing violation
 719          */
 720 
 721         io.ntcreatex.in.fname = sname2;
 722         status = smb_raw_open(cli->tree, mem_ctx, &io);
 723         CHECK_STATUS(status, NT_STATUS_OK);
 724         fnum2 = io.ntcreatex.out.file.fnum;
 725 
 726         /*
 727          * ... whereas the same stream does with unchanged access/share_access
 728          * flags
 729          */
 730 
 731         io.ntcreatex.in.fname = sname1;
 732         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
 733         status = smb_raw_open(cli->tree, mem_ctx, &io);
 734         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 735 
 736         io.ntcreatex.in.fname = sname1b;
 737         status = smb_raw_open(cli->tree, mem_ctx, &io);
 738         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
 739 
 740         io.ntcreatex.in.fname = sname1c;
 741         status = smb_raw_open(cli->tree, mem_ctx, &io);
 742         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
 743                 /* w2k returns INVALID_PARAMETER */
 744                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
 745         } else {
 746                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
 747         }
 748 
 749         io.ntcreatex.in.fname = sname1d;
 750         status = smb_raw_open(cli->tree, mem_ctx, &io);
 751         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
 752                 /* w2k returns INVALID_PARAMETER */
 753                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
 754         } else {
 755                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
 756         }
 757 
 758         io.ntcreatex.in.fname = sname2;
 759         status = smb_raw_open(cli->tree, mem_ctx, &io);
 760         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 761 
 762         io.ntcreatex.in.fname = snamew;
 763         status = smb_raw_open(cli->tree, mem_ctx, &io);
 764         CHECK_STATUS(status, NT_STATUS_OK);
 765         fnum3 = io.ntcreatex.out.file.fnum;
 766 
 767         io.ntcreatex.in.fname = snamew2;
 768         status = smb_raw_open(cli->tree, mem_ctx, &io);
 769         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
 770 
 771         ret &= check_stream_list(cli, fname, 4, four);
 772 
 773         smbcli_close(cli->tree, fnum1);
 774         smbcli_close(cli->tree, fnum2);
 775         smbcli_close(cli->tree, fnum3);
 776 
 777         if (torture_setting_bool(tctx, "samba4", true)) {
 778                 goto done;
 779         }
 780 
 781         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
 782         finfo.generic.in.file.path = fname;
 783         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
 784         CHECK_STATUS(status, NT_STATUS_OK);
 785 
 786         ret &= check_stream_list(cli, fname, 4, four);
 787 
 788         for (i=0; i < 4; i++) {
 789                 NTTIME write_time;
 790                 uint64_t stream_size;
 791                 char *path = talloc_asprintf(tctx, "%s%s",
 792                                              fname, four[i]);
 793 
 794                 char *rpath = talloc_strdup(path, path);
 795                 char *p = strrchr(rpath, ':');
 796                 /* eat :$DATA */
 797                 *p = 0;
 798                 p--;
 799                 if (*p == ':') {
 800                         /* eat ::$DATA */
 801                         *p = 0;
 802                 }
 803                 printf("(%s): i[%u][%s]\n", __location__, i, path);
 804                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 805                 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
 806                                               SEC_FILE_WRITE_ATTRIBUTE |
 807                                             SEC_RIGHTS_FILE_ALL;
 808                 io.ntcreatex.in.fname = path;
 809                 status = smb_raw_open(cli->tree, mem_ctx, &io);
 810                 CHECK_STATUS(status, NT_STATUS_OK);
 811                 fnum1 = io.ntcreatex.out.file.fnum;
 812 
 813                 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
 814                 finfo.generic.in.file.path = fname;
 815                 status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
 816                 CHECK_STATUS(status, NT_STATUS_OK);
 817 
 818                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
 819                 stinfo.generic.in.file.fnum = fnum1;
 820                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
 821                 CHECK_STATUS(status, NT_STATUS_OK);
 822                 if (!torture_setting_bool(tctx, "samba3", false)) {
 823                         CHECK_NTTIME(stinfo.all_info.out.create_time,
 824                                      finfo.all_info.out.create_time);
 825                         CHECK_NTTIME(stinfo.all_info.out.access_time,
 826                                      finfo.all_info.out.access_time);
 827                         CHECK_NTTIME(stinfo.all_info.out.write_time,
 828                                      finfo.all_info.out.write_time);
 829                         CHECK_NTTIME(stinfo.all_info.out.change_time,
 830                                      finfo.all_info.out.change_time);
 831                 }
 832                 CHECK_VALUE(stinfo.all_info.out.attrib,
 833                             finfo.all_info.out.attrib);
 834                 CHECK_VALUE(stinfo.all_info.out.size,
 835                             finfo.all_info.out.size);
 836                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
 837                             finfo.all_info.out.delete_pending);
 838                 CHECK_VALUE(stinfo.all_info.out.directory,
 839                             finfo.all_info.out.directory);
 840                 CHECK_VALUE(stinfo.all_info.out.ea_size,
 841                             finfo.all_info.out.ea_size);
 842 
 843                 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
 844                 stinfo.generic.in.file.fnum = fnum1;
 845                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
 846                 CHECK_STATUS(status, NT_STATUS_OK);
 847                 if (!torture_setting_bool(tctx, "samba3", false)) {
 848                         CHECK_STR(rpath, stinfo.name_info.out.fname.s);
 849                 }
 850 
 851                 write_time = finfo.all_info.out.write_time;
 852                 write_time += i*1000000;
 853                 write_time /= 1000000;
 854                 write_time *= 1000000;
 855 
 856                 ZERO_STRUCT(sinfo);
 857                 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
 858                 sinfo.basic_info.in.file.fnum = fnum1;
 859                 sinfo.basic_info.in.write_time = write_time;
 860                 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
 861                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
 862                 CHECK_STATUS(status, NT_STATUS_OK);
 863 
 864                 stream_size = i*8192;
 865 
 866                 ZERO_STRUCT(sinfo);
 867                 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
 868                 sinfo.end_of_file_info.in.file.fnum = fnum1;
 869                 sinfo.end_of_file_info.in.size = stream_size;
 870                 status = smb_raw_setfileinfo(cli->tree, &sinfo);
 871                 CHECK_STATUS(status, NT_STATUS_OK);
 872 
 873                 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
 874                 stinfo.generic.in.file.fnum = fnum1;
 875                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &stinfo);
 876                 CHECK_STATUS(status, NT_STATUS_OK);
 877                 if (!torture_setting_bool(tctx, "samba3", false)) {
 878                         CHECK_NTTIME(stinfo.all_info.out.write_time,
 879                                      write_time);
 880                         CHECK_VALUE(stinfo.all_info.out.attrib,
 881                                     finfo.all_info.out.attrib);
 882                 }
 883                 CHECK_VALUE(stinfo.all_info.out.size,
 884                             stream_size);
 885                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
 886                             finfo.all_info.out.delete_pending);
 887                 CHECK_VALUE(stinfo.all_info.out.directory,
 888                             finfo.all_info.out.directory);
 889                 CHECK_VALUE(stinfo.all_info.out.ea_size,
 890                             finfo.all_info.out.ea_size);
 891 
 892                 ret &= check_stream_list(cli, fname, 4, four);
 893 
 894                 smbcli_close(cli->tree, fnum1);
 895                 talloc_free(path);
 896         }
 897 
 898         printf("(%s): testing stream renames\n", __location__);
 899         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 900         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
 901                                       SEC_FILE_WRITE_ATTRIBUTE |
 902                                     SEC_RIGHTS_FILE_ALL;
 903         io.ntcreatex.in.fname = snamer1;
 904         status = smb_raw_open(cli->tree, mem_ctx, &io);
 905         CHECK_STATUS(status, NT_STATUS_OK);
 906         fnum1 = io.ntcreatex.out.file.fnum;
 907 
 908         ret &= check_stream_list(cli, fname, 5, five1);
 909 
 910         ZERO_STRUCT(sinfo);
 911         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
 912         sinfo.rename_information.in.file.fnum = fnum1;
 913         sinfo.rename_information.in.overwrite = true;
 914         sinfo.rename_information.in.root_fid = 0;
 915         sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
 916         status = smb_raw_setfileinfo(cli->tree, &sinfo);
 917         CHECK_STATUS(status, NT_STATUS_OK);
 918 
 919         ret &= check_stream_list(cli, fname, 5, five2);
 920 
 921         ZERO_STRUCT(sinfo);
 922         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
 923         sinfo.rename_information.in.file.fnum = fnum1;
 924         sinfo.rename_information.in.overwrite = false;
 925         sinfo.rename_information.in.root_fid = 0;
 926         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
 927         status = smb_raw_setfileinfo(cli->tree, &sinfo);
 928         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
 929 
 930         ret &= check_stream_list(cli, fname, 5, five2);
 931 
 932         ZERO_STRUCT(sinfo);
 933         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
 934         sinfo.rename_information.in.file.fnum = fnum1;
 935         sinfo.rename_information.in.overwrite = true;
 936         sinfo.rename_information.in.root_fid = 0;
 937         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
 938         status = smb_raw_setfileinfo(cli->tree, &sinfo);
 939         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
 940 
 941         ret &= check_stream_list(cli, fname, 5, five2);
 942 
 943         /* TODO: we need to test more rename combinations */
 944 
 945 done:
 946         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
 947         if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
 948         if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
 949         status = smbcli_unlink(cli->tree, fname);
 950         return ret;
 951 }
 952 
 953 /*
 954   test stream names
 955 */
 956 static bool test_stream_names2(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 957                                struct smbcli_state *cli,
 958                                TALLOC_CTX *mem_ctx)
 959 {
 960         NTSTATUS status;
 961         union smb_open io;
 962         const char *fname = BASEDIR "\\stream_names2.txt";
 963         bool ret = true;
 964         int fnum1 = -1;
 965         uint8_t i;
 966 
 967         printf("(%s) testing stream names\n", __location__);
 968         io.generic.level = RAW_OPEN_NTCREATEX;
 969         io.ntcreatex.in.root_fid = 0;
 970         io.ntcreatex.in.flags = 0;
 971         io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
 972         io.ntcreatex.in.create_options = 0;
 973         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
 974         io.ntcreatex.in.share_access = 0;
 975         io.ntcreatex.in.alloc_size = 0;
 976         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 977         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 978         io.ntcreatex.in.security_flags = 0;
 979         io.ntcreatex.in.fname = fname;
 980         status = smb_raw_open(cli->tree, mem_ctx, &io);
 981         CHECK_STATUS(status, NT_STATUS_OK);
 982         fnum1 = io.ntcreatex.out.file.fnum;
 983 
 984         for (i=0x01; i < 0x7F; i++) {
 985                 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
 986                                              fname, i, i);
 987                 NTSTATUS expected;
 988 
 989                 switch (i) {
 990                 case '/':/*0x2F*/
 991                 case ':':/*0x3A*/
 992                 case '\\':/*0x5C*/
 993                         expected = NT_STATUS_OBJECT_NAME_INVALID;
 994                         break;
 995                 default:
 996                         expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 997                         break;
 998                 }
 999 
1000 
1001                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1002                 io.ntcreatex.in.fname = path;
1003                 status = smb_raw_open(cli->tree, mem_ctx, &io);
1004                 if (!NT_STATUS_EQUAL(status, expected)) {
1005                         printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1006                                 __location__, fname, isprint(i)?(char)i:' ', i,
1007                                 isprint(i)?"":" (not printable)",
1008                                 nt_errstr(expected));
1009                 }
1010                 CHECK_STATUS(status, expected);
1011 
1012                 talloc_free(path);
1013         }
1014 
1015 done:
1016         if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1017         status = smbcli_unlink(cli->tree, fname);
1018         return ret;
1019 }
1020 
1021 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1022         check_fnum = true; \
1023         call_name = #call; \
1024         sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1025         sfinfo.generic.in.file.fnum = fnum; \
1026         status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1027         if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1028                 printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
1029                         nt_errstr(status), nt_errstr(rightstatus)); \
1030                 ret = false; \
1031         } \
1032         finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1033         finfo1.generic.in.file.fnum = fnum; \
1034         status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1035         if (!NT_STATUS_IS_OK(status2)) { \
1036                 printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
1037                 ret = false; \
1038         }} while (0)
1039 
1040 /*
1041   test stream renames
1042 */
1043 static bool test_stream_rename(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
1044                                    struct smbcli_state *cli,
1045                                    TALLOC_CTX *mem_ctx)
1046 {
1047         NTSTATUS status, status2;
1048         union smb_open io;
1049         const char *fname = BASEDIR "\\stream_rename.txt";
1050         const char *sname1, *sname2;
1051         union smb_fileinfo finfo1;
1052         union smb_setfileinfo sfinfo;
1053         bool ret = true;
1054         int fnum = -1;
1055         bool check_fnum;
1056         const char *call_name;
1057 
1058         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
1059         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
1060 
1061         printf("(%s) testing stream renames\n", __location__);
1062         io.generic.level = RAW_OPEN_NTCREATEX;
1063         io.ntcreatex.in.root_fid = 0;
1064         io.ntcreatex.in.flags = 0;
1065         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1066                                       SEC_FILE_WRITE_ATTRIBUTE |
1067                                     SEC_RIGHTS_FILE_ALL;
1068         io.ntcreatex.in.create_options = 0;
1069         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1070         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1071         io.ntcreatex.in.alloc_size = 0;
1072         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1073         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1074         io.ntcreatex.in.security_flags = 0;
1075         io.ntcreatex.in.fname = sname1;
1076 
1077         /* Create two streams. */
1078         status = smb_raw_open(cli->tree, mem_ctx, &io);
1079         CHECK_STATUS(status, NT_STATUS_OK);
1080         fnum = io.ntcreatex.out.file.fnum;
1081         if (fnum != -1) smbcli_close(cli->tree, fnum);
1082 
1083         io.ntcreatex.in.fname = sname2;
1084         status = smb_raw_open(cli->tree, mem_ctx, &io);
1085         CHECK_STATUS(status, NT_STATUS_OK);
1086         fnum = io.ntcreatex.out.file.fnum;
1087 
1088         if (fnum != -1) smbcli_close(cli->tree, fnum);
1089 
1090         /*
1091          * Open the second stream.
1092          */
1093 
1094         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1095         status = smb_raw_open(cli->tree, mem_ctx, &io);
1096         CHECK_STATUS(status, NT_STATUS_OK);
1097         fnum = io.ntcreatex.out.file.fnum;
1098 
1099         /*
1100          * Now rename the second stream onto the first.
1101          */
1102 
1103         ZERO_STRUCT(sfinfo);
1104 
1105         sfinfo.rename_information.in.overwrite = 1;
1106         sfinfo.rename_information.in.root_fid  = 0;
1107         sfinfo.rename_information.in.new_name  = ":Stream One";
1108         CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1109 
1110 done:
1111         if (fnum != -1) smbcli_close(cli->tree, fnum);
1112         status = smbcli_unlink(cli->tree, fname);
1113         return ret;
1114 }
1115 
1116 static bool test_stream_rename2(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
1117                                struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1118 {
1119         NTSTATUS status;
1120         union smb_open io;
1121         const char *fname1 = BASEDIR "\\stream.txt";
1122         const char *fname2 = BASEDIR "\\stream2.txt";
1123         const char *stream_name1 = ":Stream One:$DATA";
1124         const char *stream_name2 = ":Stream Two:$DATA";
1125         const char *stream_name_default = "::$DATA";
1126         const char *sname1;
1127         const char *sname2;
1128         bool ret = true;
1129         int fnum = -1;
1130         union smb_setfileinfo sinfo;
1131         union smb_rename rio;
1132 
1133         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
1134         sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
1135 
1136         io.generic.level = RAW_OPEN_NTCREATEX;
1137         io.ntcreatex.in.root_fid = 0;
1138         io.ntcreatex.in.flags = 0;
1139         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1140             SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1141         io.ntcreatex.in.create_options = 0;
1142         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1143         io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1144                                         NTCREATEX_SHARE_ACCESS_WRITE |
1145                                         NTCREATEX_SHARE_ACCESS_DELETE);
1146         io.ntcreatex.in.alloc_size = 0;
1147         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1148         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1149         io.ntcreatex.in.security_flags = 0;
1150         io.ntcreatex.in.fname = sname1;
1151 
1152         /* Open/create new stream. */
1153         status = smb_raw_open(cli->tree, mem_ctx, &io);
1154         CHECK_STATUS(status, NT_STATUS_OK);
1155 
1156         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1157 
1158         /*
1159          * Check raw rename with <base>:<stream>.
1160          */
1161         printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1162                __location__);
1163         rio.generic.level = RAW_RENAME_NTRENAME;
1164         rio.ntrename.in.old_name = sname1;
1165         rio.ntrename.in.new_name = sname2;
1166         rio.ntrename.in.attrib = 0;
1167         rio.ntrename.in.cluster_size = 0;
1168         rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1169         status = smb_raw_rename(cli->tree, &rio);
1170         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1171 
1172         /*
1173          * Check raw rename to the default stream using :<stream>.
1174          */
1175         printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1176                __location__);
1177         rio.ntrename.in.new_name = stream_name_default;
1178         status = smb_raw_rename(cli->tree, &rio);
1179         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1180 
1181         /*
1182          * Check raw rename using :<stream>.
1183          */
1184         printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1185                __location__);
1186         rio.ntrename.in.new_name = stream_name2;
1187         status = smb_raw_rename(cli->tree, &rio);
1188         CHECK_STATUS(status, NT_STATUS_OK);
1189 
1190         /*
1191          * Check raw rename of a stream to a file.
1192          */
1193         printf("(%s) Checking NTRENAME of a stream to a file\n",
1194                __location__);
1195         rio.ntrename.in.old_name = sname2;
1196         rio.ntrename.in.new_name = fname2;
1197         status = smb_raw_rename(cli->tree, &rio);
1198         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1199 
1200         /*
1201          * Check raw rename of a file to a stream.
1202          */
1203         printf("(%s) Checking NTRENAME of a file to a stream\n",
1204                __location__);
1205 
1206         /* Create the file. */
1207         io.ntcreatex.in.fname = fname2;
1208         status = smb_raw_open(cli->tree, mem_ctx, &io);
1209         CHECK_STATUS(status, NT_STATUS_OK);
1210         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1211 
1212         /* Try the rename. */
1213         rio.ntrename.in.old_name = fname2;
1214         rio.ntrename.in.new_name = sname1;
1215         status = smb_raw_rename(cli->tree, &rio);
1216         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1217 
1218         /*
1219          * Reopen the stream for trans2 renames.
1220          */
1221         io.ntcreatex.in.fname = sname2;
1222         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1223         status = smb_raw_open(cli->tree, mem_ctx, &io);
1224         CHECK_STATUS(status, NT_STATUS_OK);
1225         fnum = io.ntcreatex.out.file.fnum;
1226 
1227         /*
1228          * Check trans2 rename of a stream using :<stream>.
1229          */
1230         printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1231                __location__);
1232         ZERO_STRUCT(sinfo);
1233         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1234         sinfo.rename_information.in.file.fnum = fnum;
1235         sinfo.rename_information.in.overwrite = 1;
1236         sinfo.rename_information.in.root_fid = 0;
1237         sinfo.rename_information.in.new_name = stream_name1;
1238         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1239         CHECK_STATUS(status, NT_STATUS_OK);
1240 
1241         /*
1242          * Check trans2 rename of an overwriting stream using :<stream>.
1243          */
1244         printf("(%s) Checking trans2 rename of an overwriting stream using "
1245                ":<stream>\n", __location__);
1246 
1247         /* Create second stream. */
1248         io.ntcreatex.in.fname = sname2;
1249         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1250         status = smb_raw_open(cli->tree, mem_ctx, &io);
1251         CHECK_STATUS(status, NT_STATUS_OK);
1252         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1253 
1254         /* Rename the first stream onto the second. */
1255         sinfo.rename_information.in.file.fnum = fnum;
1256         sinfo.rename_information.in.new_name = stream_name2;
1257         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1258         CHECK_STATUS(status, NT_STATUS_OK);
1259 
1260         smbcli_close(cli->tree, fnum);
1261 
1262         /*
1263          * Reopen the stream with the new name.
1264          */
1265         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1266         io.ntcreatex.in.fname = sname2;
1267         status = smb_raw_open(cli->tree, mem_ctx, &io);
1268         CHECK_STATUS(status, NT_STATUS_OK);
1269         fnum = io.ntcreatex.out.file.fnum;
1270 
1271         /*
1272          * Check trans2 rename of a stream using <base>:<stream>.
1273          */
1274         printf("(%s) Checking trans2 rename of a stream using "
1275                "<base>:<stream>\n", __location__);
1276         sinfo.rename_information.in.file.fnum = fnum;
1277         sinfo.rename_information.in.new_name = sname1;
1278         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1279         CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1280 
1281         /*
1282          * Samba3 doesn't currently support renaming a stream to the default
1283          * stream.  This test does pass on windows.
1284          */
1285         if (torture_setting_bool(tctx, "samba3", false) ||
1286             torture_setting_bool(tctx, "samba4", false)) {
1287                 goto done;
1288         }
1289 
1290         /*
1291          * Check trans2 rename to the default stream using :<stream>.
1292          */
1293         printf("(%s) Checking trans2 rename to defaualt stream using "
1294                ":<stream>\n", __location__);
1295         sinfo.rename_information.in.file.fnum = fnum;
1296         sinfo.rename_information.in.new_name = stream_name_default;
1297         status = smb_raw_setfileinfo(cli->tree, &sinfo);
1298         CHECK_STATUS(status, NT_STATUS_OK);
1299 
1300         smbcli_close(cli->tree, fnum);
1301 
1302  done:
1303         smbcli_close(cli->tree, fnum);
1304         status = smbcli_unlink(cli->tree, fname1);
1305         status = smbcli_unlink(cli->tree, fname2);
1306         return ret;
1307 }
1308 
1309 static bool create_file_with_stream(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
1310                                     struct smbcli_state *cli,
1311                                     TALLOC_CTX *mem_ctx,
1312                                     const char *base_fname,
1313                                     const char *stream)
1314 {
1315         NTSTATUS status;
1316         bool ret = true;
1317         union smb_open io;
1318 
1319         /* Create a file with a stream */
1320         io.generic.level = RAW_OPEN_NTCREATEX;
1321         io.ntcreatex.in.root_fid = 0;
1322         io.ntcreatex.in.flags = 0;
1323         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1324             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1325         io.ntcreatex.in.create_options = 0;
1326         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1327         io.ntcreatex.in.share_access = 0;
1328         io.ntcreatex.in.alloc_size = 0;
1329         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1330         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1331         io.ntcreatex.in.security_flags = 0;
1332         io.ntcreatex.in.fname = stream;
1333 
1334         status = smb_raw_open(cli->tree, mem_ctx, &io);
1335         CHECK_STATUS(status, NT_STATUS_OK);
1336 
1337  done:
1338         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1339         return ret;
1340 }
1341 
1342 /* Test how streams interact with create dispositions */
1343 static bool test_stream_create_disposition(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
1344                                            struct smbcli_state *cli,
1345                                            TALLOC_CTX *mem_ctx)
1346 {
1347         NTSTATUS status;
1348         union smb_open io;
1349         const char *fname = BASEDIR "\\stream.txt";
1350         const char *stream = "Stream One:$DATA";
1351         const char *fname_stream;
1352         const char *default_stream_name = "::$DATA";
1353         const char *stream_list[2];
1354         bool ret = true;
1355         int fnum = -1;
1356 
1357         fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1358 
1359         stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
1360         stream_list[1] = default_stream_name;
1361 
1362         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1363                                      fname_stream)) {
1364                 goto done;
1365         }
1366 
1367         /* Open the base file with OPEN */
1368         io.generic.level = RAW_OPEN_NTCREATEX;
1369         io.ntcreatex.in.root_fid = 0;
1370         io.ntcreatex.in.flags = 0;
1371         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1372             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1373         io.ntcreatex.in.create_options = 0;
1374         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1375         io.ntcreatex.in.share_access = 0;
1376         io.ntcreatex.in.alloc_size = 0;
1377         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1378         io.ntcreatex.in.security_flags = 0;
1379         io.ntcreatex.in.fname = fname;
1380 
1381         /*
1382          * check ntcreatex open: sanity check
1383          */
1384         printf("(%s) Checking ntcreatex disp: open\n", __location__);
1385         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1386         status = smb_raw_open(cli->tree, mem_ctx, &io);
1387         CHECK_STATUS(status, NT_STATUS_OK);
1388         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1389         if (!check_stream_list(cli, fname, 2, stream_list)) {
1390                 goto done;
1391         }
1392 
1393         /*
1394          * check ntcreatex overwrite
1395          */
1396         printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1397         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1398         status = smb_raw_open(cli->tree, mem_ctx, &io);
1399         CHECK_STATUS(status, NT_STATUS_OK);
1400         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1401         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1402                 goto done;
1403         }
1404 
1405         /*
1406          * check ntcreatex overwrite_if
1407          */
1408         printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1409         smbcli_unlink(cli->tree, fname);
1410         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1411                                      fname_stream)) {
1412                 goto done;
1413         }
1414 
1415         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1416         status = smb_raw_open(cli->tree, mem_ctx, &io);
1417         CHECK_STATUS(status, NT_STATUS_OK);
1418         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1419         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1420                 goto done;
1421         }
1422 
1423         /*
1424          * check ntcreatex supersede
1425          */
1426         printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1427         smbcli_unlink(cli->tree, fname);
1428         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1429                                      fname_stream)) {
1430                 goto done;
1431         }
1432 
1433         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1434         status = smb_raw_open(cli->tree, mem_ctx, &io);
1435         CHECK_STATUS(status, NT_STATUS_OK);
1436         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1437         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1438                 goto done;
1439         }
1440 
1441         /*
1442          * check ntcreatex overwrite_if on a stream.
1443          */
1444         printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1445                __location__);
1446         smbcli_unlink(cli->tree, fname);
1447         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1448                                      fname_stream)) {
1449                 goto done;
1450         }
1451 
1452         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1453         io.ntcreatex.in.fname = fname_stream;
1454         status = smb_raw_open(cli->tree, mem_ctx, &io);
1455         CHECK_STATUS(status, NT_STATUS_OK);
1456         smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1457         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1458                 goto done;
1459         }
1460 
1461         /*
1462          * check openx overwrite_if
1463          */
1464         printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1465         smbcli_unlink(cli->tree, fname);
1466         if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
1467                                      fname_stream)) {
1468                 goto done;
1469         }
1470 
1471         io.openx.level = RAW_OPEN_OPENX;
1472         io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1473         io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
1474         io.openx.in.search_attrs = 0;
1475         io.openx.in.file_attrs = 0;
1476         io.openx.in.write_time = 0;
1477         io.openx.in.size = 1024*1024;
1478         io.openx.in.timeout = 0;
1479         io.openx.in.fname = fname;
1480 
1481         io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1482         status = smb_raw_open(cli->tree, mem_ctx, &io);
1483         CHECK_STATUS(status, NT_STATUS_OK);
1484         smbcli_close(cli->tree, io.openx.out.file.fnum);
1485         if (!check_stream_list(cli, fname, 1, &default_stream_name)) {
1486                 goto done;
1487         }
1488 
1489  done:
1490         smbcli_close(cli->tree, fnum);
1491         smbcli_unlink(cli->tree, fname);
1492         return ret;
1493 }
1494 
1495 /* Test streaminfo with enough streams on a file to fill up the buffer.  */
1496 static bool test_stream_large_streaminfo(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
1497                                          struct smbcli_state *cli,
1498                                          TALLOC_CTX *mem_ctx)
1499 {
1500 #define LONG_STREAM_SIZE 2
1501         char *lstream_name;
1502         const char *fname = BASEDIR "\\stream.txt";
1503         const char *fname_stream;
1504         NTSTATUS status;
1505         bool ret = true;
1506         int i;
1507         union smb_fileinfo finfo;
1508 
1509         lstream_name = talloc_array(mem_ctx, char, LONG_STREAM_SIZE);
1510 
1511         for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1512                 lstream_name[i] = (char)('a' + i%26);
1513         }
1514         lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1515 
1516         printf("(%s) Creating a file with a lot of streams\n", __location__);
1517         for (i = 0; i < 10000; i++) {
1518                 fname_stream = talloc_asprintf(mem_ctx, "%s:%s%d", fname,
1519                                                lstream_name, i);
1520                 ret = create_file_with_stream(tctx, cli, mem_ctx, fname,
1521                                               fname_stream);
1522                 if (!ret) {
1523                         goto done;
1524                 }
1525         }
1526 
1527         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1528         finfo.generic.in.file.path = fname;
1529 
1530         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1531         CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1532 
1533  done:
1534         smbcli_unlink(cli->tree, fname);
1535         return ret;
1536 }
1537 
1538 /* Test the effect of setting attributes on a stream. */
1539 static bool test_stream_attributes(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
1540                                          struct smbcli_state *cli,
1541                                          TALLOC_CTX *mem_ctx)
1542 {
1543         bool ret = true;
1544         NTSTATUS status;
1545         union smb_open io;
1546         const char *fname = BASEDIR "\\stream_attr.txt";
1547         const char *stream = "Stream One:$DATA";
1548         const char *fname_stream;
1549         int fnum = -1;
1550         union smb_fileinfo finfo;
1551         union smb_setfileinfo sfinfo;
1552         time_t basetime = (time(NULL) - 86400) & ~1;
1553 
1554         printf ("(%s) testing attribute setting on stream\n", __location__);
1555 
1556         fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1557 
1558         /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1559         ret = create_file_with_stream(tctx, cli, mem_ctx, fname,
1560                                       fname_stream);
1561         if (!ret) {
1562                 goto done;
1563         }
1564 
1565         ZERO_STRUCT(finfo);
1566         finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1567         finfo.generic.in.file.path = fname;
1568         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1569         CHECK_STATUS(status, NT_STATUS_OK);
1570 
1571         if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1572                 printf("(%s) Incorrect attrib %x - should be %x\n", \
1573                        __location__, (unsigned int)finfo.basic_info.out.attrib,
1574                         (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1575                 ret = false;
1576                 goto done;
1577         }
1578 
1579         /* Now open the stream name. */
1580 
1581         io.generic.level = RAW_OPEN_NTCREATEX;
1582         io.ntcreatex.in.root_fid = 0;
1583         io.ntcreatex.in.flags = 0;
1584         io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1585             SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1586         io.ntcreatex.in.create_options = 0;
1587         io.ntcreatex.in.file_attr = 0;
1588         io.ntcreatex.in.share_access = 0;
1589         io.ntcreatex.in.alloc_size = 0;
1590         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1591         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1592         io.ntcreatex.in.security_flags = 0;
1593         io.ntcreatex.in.fname = fname_stream;
1594 
1595         status = smb_raw_open(cli->tree, mem_ctx, &io);
1596         CHECK_STATUS(status, NT_STATUS_OK);
1597 
1598         fnum = io.ntcreatex.out.file.fnum;
1599 
1600         /* Change the attributes + time on the stream fnum. */
1601         ZERO_STRUCT(sfinfo);
1602         sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1603         unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1604 
1605         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1606         sfinfo.generic.in.file.fnum = fnum;
1607         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1608         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { 
1609                 printf("(%s) %s - %s (should be %s)\n", __location__, "SETATTR", 
1610                         nt_errstr(status), nt_errstr(NT_STATUS_OK));
1611                 ret = false;
1612                 goto done;
1613         }
1614 
1615         smbcli_close(cli->tree, fnum);
1616         fnum = -1;
1617 
1618         ZERO_STRUCT(finfo);
1619         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1620         finfo.generic.in.file.path = fname;
1621         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1622         if (!NT_STATUS_IS_OK(status)) {
1623                 printf("(%s) %s pathinfo - %s\n", __location__, "SETATTRE", nt_errstr(status));
1624                 ret = false;
1625                 goto done;
1626         }
1627 
1628         if (finfo.all_info.out.attrib != FILE_ATTRIBUTE_READONLY) {
1629                 printf("(%s) attrib incorrect. Was 0x%x, should be 0x%x\n",
1630                         __location__,
1631                         (unsigned int)finfo.all_info.out.attrib,
1632                         (unsigned int)FILE_ATTRIBUTE_READONLY);
1633                 ret = false;
1634                 goto done;
1635         }
1636 
1637         if (nt_time_to_unix(finfo.all_info.out.write_time) != basetime) {
1638                 printf("(%s) time incorrect.\n",
1639                         __location__);
1640                 ret = false;
1641                 goto done;
1642         }
1643 
1644  done:
1645 
1646         if (fnum != -1) {
1647                 smbcli_close(cli->tree, fnum);
1648         }
1649         smbcli_unlink(cli->tree, fname);
1650         return ret;
1651 }
1652 
1653 /* 
1654    basic testing of streams calls
1655 */
1656 bool torture_raw_streams(struct torture_context *torture, 
     /* [<][>][^][v][top][bottom][index][help] */
1657                          struct smbcli_state *cli)
1658 {
1659         bool ret = true;
1660 
1661         if (!torture_setup_dir(cli, BASEDIR)) {
1662                 return false;
1663         }
1664 
1665         ret &= test_stream_dir(torture, cli, torture);
1666         smb_raw_exit(cli->session);
1667         ret &= test_stream_io(torture, cli, torture);
1668         smb_raw_exit(cli->session);
1669         ret &= test_stream_sharemodes(torture, cli, torture);
1670         smb_raw_exit(cli->session);
1671         if (!torture_setting_bool(torture, "samba4", false)) {
1672                 ret &= test_stream_delete(torture, cli, torture);
1673         }
1674         ret &= test_stream_names(torture, cli, torture);
1675         smb_raw_exit(cli->session);
1676         ret &= test_stream_names2(torture, cli, torture);
1677         smb_raw_exit(cli->session);
1678         ret &= test_stream_rename(torture, cli, torture);
1679         smb_raw_exit(cli->session);
1680         ret &= test_stream_rename2(torture, cli, torture);
1681         smb_raw_exit(cli->session);
1682         ret &= test_stream_create_disposition(torture, cli, torture);
1683         smb_raw_exit(cli->session);
1684 
1685         ret &= test_stream_attributes(torture, cli, torture);
1686         smb_raw_exit(cli->session);
1687 
1688         /* ret &= test_stream_large_streaminfo(torture, cli, torture); */
1689 /*      smb_raw_exit(cli->session); */
1690 
1691         smbcli_deltree(cli->tree, BASEDIR);
1692 
1693         return ret;
1694 }

/* [<][>][^][v][top][bottom][index][help] */