LCOV - code coverage report
Current view: top level - source4/torture/raw - notify.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 915 941 97.2 %
Date: 2024-06-13 04:01:37 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    basic raw test suite for change notify
       4             :    Copyright (C) Andrew Tridgell 2003
       5             :    
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             :    
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             :    
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "libcli/raw/libcliraw.h"
      22             : #include "libcli/raw/raw_proto.h"
      23             : #include "libcli/libcli.h"
      24             : #include "system/filesys.h"
      25             : #include "torture/util.h"
      26             : #include "torture/raw/proto.h"
      27             : #include "lib/events/events.h"
      28             : 
      29             : #define BASEDIR "\\test_notify"
      30             : 
      31             : #define CHECK_WSTR(tctx, field, value, flags) \
      32             : do { \
      33             :         torture_assert_str_equal(tctx, field.s, value, "values don't match"); \
      34             :         torture_assert(tctx, \
      35             :                        !wire_bad_flags(&field, STR_UNICODE, cli->transport), \
      36             :                        "wire_bad_flags"); \
      37             : } while (0)
      38             : 
      39             : #define BASEDIR_CN1_DIR BASEDIR "_CN1_DIR"
      40             : 
      41             : /* 
      42             :    basic testing of change notify on directories
      43             : */
      44           1 : static bool test_notify_dir(struct torture_context *tctx,
      45             :                             struct smbcli_state *cli,
      46             :                             struct smbcli_state *cli2)
      47             : {
      48           1 :         bool ret = true;
      49             :         NTSTATUS status;
      50             :         union smb_notify notify;
      51             :         union smb_open io;
      52             :         union smb_close cl;
      53             :         int i, count, fnum, fnum2;
      54             :         struct smbcli_request *req, *req2;
      55             :         extern int torture_numops;
      56             : 
      57           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
      58             : 
      59           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DIR),
      60             :                        "Failed to setup up test directory: " BASEDIR_CN1_DIR);
      61             : 
      62             :         /*
      63             :           get a handle on the directory
      64             :         */
      65           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
      66           1 :         io.ntcreatex.in.root_fid.fnum = 0;
      67           1 :         io.ntcreatex.in.flags = 0;
      68           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
      69           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
      70           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
      71           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
      72           1 :         io.ntcreatex.in.alloc_size = 0;
      73           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
      74           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
      75           1 :         io.ntcreatex.in.security_flags = 0;
      76           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_DIR;
      77             : 
      78           1 :         status = smb_raw_open(cli->tree, tctx, &io);
      79           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      80             :                                         "smb_raw_open");
      81           1 :         fnum = io.ntcreatex.out.file.fnum;
      82             : 
      83           1 :         status = smb_raw_open(cli->tree, tctx, &io);
      84           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      85             :                                         "smb_raw_open");
      86           1 :         fnum2 = io.ntcreatex.out.file.fnum;
      87             : 
      88             :         /* ask for a change notify,
      89             :            on file or directory name changes */
      90           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
      91           1 :         notify.nttrans.in.buffer_size = 1000;
      92           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
      93           1 :         notify.nttrans.in.file.fnum = fnum;
      94           1 :         notify.nttrans.in.recursive = true;
      95             : 
      96           1 :         torture_comment(tctx, "Testing notify cancel\n");
      97             : 
      98           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
      99           1 :         smb_raw_ntcancel(req);
     100           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     101           1 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED,
     102             :                                            ret, done,
     103             :                                            "smb_raw_changenotify_recv");
     104             : 
     105           1 :         torture_comment(tctx, "Testing notify mkdir\n");
     106             : 
     107           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     108           1 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     109             : 
     110           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     111           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     112             :                                         "smb_raw_changenotify_recv");
     113             : 
     114           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     115             :                                       1, ret, done, "more than one change");
     116           1 :         torture_assert_int_equal_goto(tctx,
     117             :                                       notify.nttrans.out.changes[0].action,
     118             :                                       NOTIFY_ACTION_ADDED, ret, done,
     119             :                                       "wrong action (exp: ADDED)");
     120           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     121             :                    STR_UNICODE);
     122             : 
     123           1 :         torture_comment(tctx, "Testing notify rmdir\n");
     124             : 
     125           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     126           1 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     127             : 
     128           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     129           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     130             :                                         "smb_raw_changenotify_recv");
     131           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     132             :                                       1, ret, done, "more than one change");
     133           1 :         torture_assert_int_equal_goto(tctx,
     134             :                                       notify.nttrans.out.changes[0].action,
     135             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     136             :                                       "wrong action (exp: REMOVED)");
     137           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     138             :                    STR_UNICODE);
     139             : 
     140           1 :         torture_comment(tctx, "Testing notify mkdir - rmdir - mkdir - rmdir\n");
     141             : 
     142           1 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     143           1 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     144           1 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     145           1 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     146           1 :         smb_msleep(200);
     147           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     148           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     149           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     150             :                                         "smb_raw_changenotify_recv");
     151           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     152             :                                       4, ret, done, "wrong number of changes");
     153           1 :         torture_assert_int_equal_goto(tctx,
     154             :                                       notify.nttrans.out.changes[0].action,
     155             :                                       NOTIFY_ACTION_ADDED, ret, done,
     156             :                                       "wrong action (exp: ADDED)");
     157           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     158             :                    STR_UNICODE);
     159           1 :         torture_assert_int_equal_goto(tctx,
     160             :                                       notify.nttrans.out.changes[1].action,
     161             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     162             :                                       "wrong action (exp: REMOVED)");
     163           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
     164             :                    STR_UNICODE);
     165           1 :         torture_assert_int_equal_goto(tctx,
     166             :                                       notify.nttrans.out.changes[2].action,
     167             :                                       NOTIFY_ACTION_ADDED, ret, done,
     168             :                                       "wrong action (exp: ADDED)");
     169           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subdir-name",
     170             :                    STR_UNICODE);
     171           1 :         torture_assert_int_equal_goto(tctx,
     172             :                                       notify.nttrans.out.changes[3].action,
     173             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     174             :                                       "wrong action (exp: REMOVED)");
     175           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name, "subdir-name",
     176             :                    STR_UNICODE);
     177             : 
     178           1 :         count = torture_numops;
     179           1 :         torture_comment(tctx, "Testing buffered notify on create of %d files\n", count);
     180          11 :         for (i=0;i<count;i++) {
     181          10 :                 char *fname = talloc_asprintf(cli,
     182             :                                 BASEDIR_CN1_DIR "\\test%d.txt",
     183             :                                 i);
     184          10 :                 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
     185          10 :                 torture_assert_int_not_equal_goto(tctx, fnum3, -1, ret, done,
     186             :                         talloc_asprintf(tctx, "Failed to create %s - %s",
     187             :                                         fname, smbcli_errstr(cli->tree)));
     188          10 :                 talloc_free(fname);
     189          10 :                 smbcli_close(cli->tree, fnum3);
     190             :         }
     191             : 
     192             :         /* (1st notify) setup a new notify on a different directory handle.
     193             :            This new notify won't see the events above. */
     194           1 :         notify.nttrans.in.file.fnum = fnum2;
     195           1 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     196             : 
     197             :         /* (2nd notify) whereas this notify will see the above buffered events,
     198             :            and it directly returns the buffered events */
     199           1 :         notify.nttrans.in.file.fnum = fnum;
     200           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     201             : 
     202           1 :         status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
     203           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
     204             :                                            NT_STATUS_OBJECT_NAME_NOT_FOUND,
     205             :                                            ret, done,
     206             :                                            "smbcli_unlink");
     207             : 
     208             :         /* (1st unlink) as the 2nd notify directly returns,
     209             :            this unlink is only seen by the 1st notify and 
     210             :            the 3rd notify (later) */
     211           1 :         torture_comment(tctx, "Testing notify on unlink for the first file\n");
     212           1 :         status = smbcli_unlink(cli2->tree, BASEDIR_CN1_DIR "\\test0.txt");
     213           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     214             :                                         "smbcli_unlink");
     215             : 
     216             :         /* receive the reply from the 2nd notify */
     217           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     218           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     219             :                                         "smb_raw_changenotify_recv");
     220             : 
     221           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     222             :                                       count, ret, done,
     223             :                                       "wrong number of changes");
     224          10 :         for (i=1;i<count;i++) {
     225           9 :                 torture_assert_int_equal_goto(tctx,
     226             :                                         notify.nttrans.out.changes[i].action,
     227             :                                         NOTIFY_ACTION_ADDED, ret, done,
     228             :                                         "wrong action (exp: ADDED)");
     229             :         }
     230           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
     231             :                    STR_UNICODE);
     232             : 
     233           1 :         torture_comment(tctx, "and now from the 1st notify\n");
     234           1 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     235           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     236             :                                         "smb_raw_changenotify_recv");
     237           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     238             :                                       1, ret, done, "wrong number of changes");
     239           1 :         torture_assert_int_equal_goto(tctx,
     240             :                                       notify.nttrans.out.changes[0].action,
     241             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     242             :                                       "wrong action (exp: REMOVED)");
     243           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
     244             :                    STR_UNICODE);
     245             : 
     246           1 :         torture_comment(tctx, "(3rd notify) this notify will only see the 1st unlink\n");
     247           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     248             : 
     249           1 :         status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
     250           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
     251             :                                            NT_STATUS_OBJECT_NAME_NOT_FOUND,
     252             :                                            ret, done,
     253             :                                            "smbcli_unlink");
     254             : 
     255           1 :         torture_comment(tctx, "Testing notify on wildcard unlink for %d files\n", count-1);
     256             :         /* (2nd unlink) do a wildcard unlink */
     257           1 :         status = smbcli_unlink_wcard(cli2->tree, BASEDIR_CN1_DIR "\\test*.txt");
     258           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     259             :                                         "smb_raw_changenotify_recv");
     260             : 
     261             :         /* receive the 3rd notify */
     262           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     263           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     264             :                                         "smb_raw_changenotify_recv");
     265           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     266             :                                       1, ret, done, "wrong number of changes");
     267           1 :         torture_assert_int_equal_goto(tctx,
     268             :                                       notify.nttrans.out.changes[0].action,
     269             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     270             :                                       "wrong action (exp: REMOVED)");
     271           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
     272             :                    STR_UNICODE);
     273             : 
     274             :         /* and we now see the rest of the unlink calls on both directory handles */
     275           1 :         notify.nttrans.in.file.fnum = fnum;
     276           1 :         sleep(3);
     277           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     278           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     279           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     280             :                                         "smb_raw_changenotify_recv");
     281           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     282             :                                       count - 1, ret, done,
     283             :                                       "wrong number of changes");
     284          10 :         for (i=0;i<notify.nttrans.out.num_changes;i++) {
     285           9 :                 torture_assert_int_equal_goto(tctx,
     286             :                                         notify.nttrans.out.changes[i].action,
     287             :                                         NOTIFY_ACTION_REMOVED, ret, done,
     288             :                                         "wrong action (exp: REMOVED)");
     289             :         }
     290           1 :         notify.nttrans.in.file.fnum = fnum2;
     291           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     292           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     293           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     294             :                                         "smb_raw_changenotify_recv");
     295           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     296             :                                       count - 1, ret, done,
     297             :                                       "wrong number of changes");
     298          10 :         for (i=0;i<notify.nttrans.out.num_changes;i++) {
     299           9 :                 torture_assert_int_equal_goto(tctx,
     300             :                                         notify.nttrans.out.changes[i].action,
     301             :                                         NOTIFY_ACTION_REMOVED, ret, done,
     302             :                                         "wrong action (exp: REMOVED)");
     303             :         }
     304             : 
     305           1 :         torture_comment(tctx, "Testing if a close() on the dir handle triggers the notify reply\n");
     306             : 
     307           1 :         notify.nttrans.in.file.fnum = fnum;
     308           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     309             : 
     310           1 :         cl.close.level = RAW_CLOSE_CLOSE;
     311           1 :         cl.close.in.file.fnum = fnum;
     312           1 :         cl.close.in.write_time = 0;
     313           1 :         status = smb_raw_close(cli->tree, &cl);
     314           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     315             :                                         "smb_raw_close");
     316             : 
     317           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     318           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     319             :                                         "smb_raw_changenotify_recv");
     320           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     321             :                                       0, ret, done, "no changes expected");
     322             : 
     323           2 : done:
     324           1 :         smb_raw_exit(cli->session);
     325           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_DIR);
     326           1 :         return ret;
     327             : }
     328             : 
     329             : /*
     330             :  * Check notify reply for a rename action. Not sure if this is a valid thing
     331             :  * to do, but depending on timing between inotify and messaging we get the
     332             :  * add/remove/modify in any order. This routines tries to find the action/name
     333             :  * pair in any of the three following notify_changes.
     334             :  */
     335             : 
     336           6 : static bool check_rename_reply(struct torture_context *tctx,
     337             :                                struct smbcli_state *cli,
     338             :                                int line,
     339             :                                struct notify_changes *actions,
     340             :                                uint32_t action, const char *name)
     341             : {
     342             :         int i;
     343             : 
     344          12 :         for (i=0; i<3; i++) {
     345          12 :                 if (actions[i].action == action) {
     346           6 :                         CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
     347           6 :                         return true;
     348             :                 }
     349             :         }
     350             : 
     351           0 :         torture_result(tctx, TORTURE_FAIL,
     352             :                        __location__": (%d) expected action %d, not found\n",
     353             :                        line, action);
     354           0 :         return false;
     355             : }
     356             : 
     357             : /* 
     358             :    testing of recursive change notify
     359             : */
     360             : 
     361             : #define BASEDIR_CN1_RECUR BASEDIR "_CN1_RECUR"
     362             : 
     363           1 : static bool test_notify_recursive(struct torture_context *tctx,
     364             :                                   struct smbcli_state *cli,
     365             :                                   struct smbcli_state *cli2)
     366             : {
     367           1 :         bool ret = true;
     368             :         NTSTATUS status;
     369             :         union smb_notify notify;
     370             :         union smb_open io;
     371             :         int fnum;
     372             :         struct smbcli_request *req1, *req2;
     373             : 
     374           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY WITH RECURSION\n");
     375             : 
     376           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_RECUR),
     377             :                        "Failed to setup up test directory: " BASEDIR_CN1_RECUR);
     378             : 
     379             :         /*
     380             :           get a handle on the directory
     381             :         */
     382           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
     383           1 :         io.ntcreatex.in.root_fid.fnum = 0;
     384           1 :         io.ntcreatex.in.flags = 0;
     385           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
     386           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     387           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
     388           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
     389           1 :         io.ntcreatex.in.alloc_size = 0;
     390           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
     391           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
     392           1 :         io.ntcreatex.in.security_flags = 0;
     393           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_RECUR;
     394             : 
     395           1 :         status = smb_raw_open(cli->tree, tctx, &io);
     396           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     397             :                                         "smb_raw_open");
     398           1 :         fnum = io.ntcreatex.out.file.fnum;
     399             : 
     400             :         /* ask for a change notify, on file or directory name
     401             :            changes. Setup both with and without recursion */
     402           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
     403           1 :         notify.nttrans.in.buffer_size = 1000;
     404           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
     405           1 :         notify.nttrans.in.file.fnum = fnum;
     406             : 
     407           1 :         notify.nttrans.in.recursive = true;
     408           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     409             : 
     410           1 :         notify.nttrans.in.recursive = false;
     411           1 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     412             : 
     413             :         /* cancel initial requests so the buffer is setup */
     414           1 :         smb_raw_ntcancel(req1);
     415           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     416           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
     417             :                                            NT_STATUS_CANCELLED,
     418             :                                            ret, done,
     419             :                                            "smb_raw_changenotify_recv");
     420             : 
     421           1 :         smb_raw_ntcancel(req2);
     422           1 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     423           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
     424             :                                            NT_STATUS_CANCELLED,
     425             :                                            ret, done,
     426             :                                            "smb_raw_changenotify_recv");
     427             : 
     428             :         /*
     429             :          * Make notifies a bit more interesting in a cluster by doing
     430             :          * the changes against different nodes with --unclist
     431             :          */
     432           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name");
     433           1 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1");
     434           1 :         smbcli_close(cli->tree, 
     435             :                      smbcli_open(cli->tree,
     436             :                                 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
     437             :                                 O_CREAT, 0));
     438           1 :         smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1",
     439             :                       BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
     440           1 :         smbcli_rename(cli->tree,
     441             :                 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
     442             :                 BASEDIR_CN1_RECUR "\\subname2-r");
     443           1 :         smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subname2-r",
     444             :                       BASEDIR_CN1_RECUR "\\subname3-r");
     445             : 
     446           1 :         notify.nttrans.in.completion_filter = 0;
     447           1 :         notify.nttrans.in.recursive = true;
     448           1 :         smb_msleep(200);
     449           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     450             : 
     451           1 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
     452           1 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name");
     453           1 :         smbcli_unlink(cli->tree, BASEDIR_CN1_RECUR "\\subname3-r");
     454             : 
     455           1 :         smb_msleep(200);
     456           1 :         notify.nttrans.in.recursive = false;
     457           1 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     458             : 
     459           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     460           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     461             :                                         "smb_raw_changenotify_recv");
     462             : 
     463           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     464             :                                       11, ret, done, "wrong number of changes");
     465           1 :         torture_assert_int_equal_goto(tctx,
     466             :                                       notify.nttrans.out.changes[0].action,
     467             :                                       NOTIFY_ACTION_ADDED, ret, done,
     468             :                                       "wrong action (exp: ADDED)");
     469           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     470             :                    STR_UNICODE);
     471           1 :         torture_assert_int_equal_goto(tctx,
     472             :                                       notify.nttrans.out.changes[1].action,
     473             :                                       NOTIFY_ACTION_ADDED, ret, done,
     474             :                                       "wrong action (exp: ADDED)");
     475           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name,
     476             :                    "subdir-name\\subname1", STR_UNICODE);
     477           1 :         torture_assert_int_equal_goto(tctx,
     478             :                                       notify.nttrans.out.changes[2].action,
     479             :                                       NOTIFY_ACTION_ADDED, ret, done,
     480             :                                       "wrong action (exp: ADDED)");
     481           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name,
     482             :                    "subdir-name\\subname2", STR_UNICODE);
     483           1 :         torture_assert_int_equal_goto(tctx,
     484             :                                       notify.nttrans.out.changes[3].action,
     485             :                                       NOTIFY_ACTION_OLD_NAME, ret, done,
     486             :                                       "wrong action (exp: OLD_NAME)");
     487           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name,
     488             :                    "subdir-name\\subname1", STR_UNICODE);
     489           1 :         torture_assert_int_equal_goto(tctx,
     490             :                                       notify.nttrans.out.changes[4].action,
     491             :                                       NOTIFY_ACTION_NEW_NAME, ret, done,
     492             :                                       "wrong action (exp: NEW_NAME)");
     493           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[4].name,
     494             :                    "subdir-name\\subname1-r", STR_UNICODE);
     495             : 
     496           1 :         ret &= check_rename_reply(tctx,
     497           1 :                 cli, __LINE__, &notify.nttrans.out.changes[5],
     498             :                 NOTIFY_ACTION_ADDED, "subname2-r");
     499           1 :         ret &= check_rename_reply(tctx,
     500           1 :                 cli, __LINE__, &notify.nttrans.out.changes[5],
     501             :                 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
     502           1 :         ret &= check_rename_reply(tctx,
     503           1 :                 cli, __LINE__, &notify.nttrans.out.changes[5],
     504             :                 NOTIFY_ACTION_MODIFIED, "subname2-r");
     505             :                 
     506           1 :         ret &= check_rename_reply(tctx,
     507           1 :                 cli, __LINE__, &notify.nttrans.out.changes[8],
     508             :                 NOTIFY_ACTION_OLD_NAME, "subname2-r");
     509           1 :         ret &= check_rename_reply(tctx,
     510           1 :                 cli, __LINE__, &notify.nttrans.out.changes[8],
     511             :                 NOTIFY_ACTION_NEW_NAME, "subname3-r");
     512           1 :         ret &= check_rename_reply(tctx,
     513           1 :                 cli, __LINE__, &notify.nttrans.out.changes[8],
     514             :                 NOTIFY_ACTION_MODIFIED, "subname3-r");
     515             : 
     516           1 :         if (!ret) {
     517           0 :                 goto done;
     518             :         }
     519             : 
     520           1 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     521           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     522             :                                         "smb_raw_changenotify_recv");
     523             : 
     524           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     525             :                                       3, ret, done, "wrong number of changes");
     526           1 :         torture_assert_int_equal_goto(tctx,
     527             :                                       notify.nttrans.out.changes[0].action,
     528             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     529             :                                       "wrong action (exp: REMOVED)");
     530           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name,
     531             :                    "subdir-name\\subname1-r", STR_UNICODE);
     532           1 :         torture_assert_int_equal_goto(tctx,
     533             :                                       notify.nttrans.out.changes[1].action,
     534             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     535             :                                       "wrong action (exp: REMOVED)");
     536           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
     537             :                    STR_UNICODE);
     538           1 :         torture_assert_int_equal_goto(tctx,
     539             :                                       notify.nttrans.out.changes[2].action,
     540             :                                       NOTIFY_ACTION_REMOVED, ret, done,
     541             :                                       "wrong action (exp: REMOVED)");
     542           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subname3-r",
     543             :                    STR_UNICODE);
     544             : 
     545           1 : done:
     546           1 :         smb_raw_exit(cli->session);
     547           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_RECUR);
     548           1 :         return ret;
     549             : }
     550             : 
     551             : /* 
     552             :    testing of change notify mask change
     553             : */
     554             : 
     555             : #define BASEDIR_CN1_CNMC BASEDIR "_CN1_CNMC"
     556             : 
     557           1 : static bool test_notify_mask_change(struct torture_context *tctx,
     558             :                                     struct smbcli_state *cli)
     559             : {
     560           1 :         bool ret = true;
     561             :         NTSTATUS status;
     562             :         union smb_notify notify;
     563             :         union smb_open io;
     564             :         int fnum;
     565             :         struct smbcli_request *req1, *req2;
     566             : 
     567           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
     568             : 
     569           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_CNMC),
     570             :                        "Failed to setup up test directory: " BASEDIR_CN1_CNMC);
     571             : 
     572             :         /*
     573             :           get a handle on the directory
     574             :         */
     575           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
     576           1 :         io.ntcreatex.in.root_fid.fnum = 0;
     577           1 :         io.ntcreatex.in.flags = 0;
     578           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
     579           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     580           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
     581           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
     582           1 :         io.ntcreatex.in.alloc_size = 0;
     583           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
     584           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
     585           1 :         io.ntcreatex.in.security_flags = 0;
     586           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_CNMC;
     587             : 
     588           1 :         status = smb_raw_open(cli->tree, tctx, &io);
     589           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     590             :                                         "smb_raw_open");
     591           1 :         fnum = io.ntcreatex.out.file.fnum;
     592             : 
     593             :         /* ask for a change notify, on file or directory name
     594             :            changes. Setup both with and without recursion */
     595           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
     596           1 :         notify.nttrans.in.buffer_size = 1000;
     597           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
     598           1 :         notify.nttrans.in.file.fnum = fnum;
     599             : 
     600           1 :         notify.nttrans.in.recursive = true;
     601           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     602             : 
     603           1 :         notify.nttrans.in.recursive = false;
     604           1 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     605             : 
     606             :         /* cancel initial requests so the buffer is setup */
     607           1 :         smb_raw_ntcancel(req1);
     608           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     609           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
     610             :                                            NT_STATUS_CANCELLED,
     611             :                                            ret, done,
     612             :                                            "smb_raw_changenotify_recv");
     613             : 
     614           1 :         smb_raw_ntcancel(req2);
     615           1 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     616           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
     617             :                                            NT_STATUS_CANCELLED,
     618             :                                            ret, done,
     619             :                                            "smb_raw_changenotify_recv");
     620             : 
     621           1 :         notify.nttrans.in.recursive = true;
     622           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     623             : 
     624             :         /* Set to hidden then back again. */
     625           1 :         smbcli_close(cli->tree,
     626             :                 smbcli_open(cli->tree,BASEDIR_CN1_CNMC "\\tname1", O_CREAT, 0));
     627           1 :         smbcli_setatr(cli->tree, BASEDIR_CN1_CNMC "\\tname1",
     628             :                 FILE_ATTRIBUTE_HIDDEN, 0);
     629           1 :         smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\tname1");
     630             : 
     631           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     632           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     633             :                                         "smb_raw_changenotify_recv");
     634             : 
     635           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     636             :                                       1, ret, done, "wrong number of changes");
     637           1 :         torture_assert_int_equal_goto(tctx,
     638             :                                       notify.nttrans.out.changes[0].action,
     639             :                                       NOTIFY_ACTION_MODIFIED, ret, done,
     640             :                                       "wrong action (exp: MODIFIED)");
     641           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
     642             :                    STR_UNICODE);
     643             : 
     644             :         /* Now try and change the mask to include other events.
     645             :          * This should not work - once the mask is set on a directory
     646             :          * fnum it seems to be fixed until the fnum is closed. */
     647             : 
     648           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
     649           1 :         notify.nttrans.in.recursive = true;
     650           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     651             : 
     652           1 :         notify.nttrans.in.recursive = false;
     653           1 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     654             : 
     655           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
     656           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1");
     657           1 :         smbcli_close(cli->tree, 
     658             :                      smbcli_open(cli->tree,
     659             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
     660             :                         O_CREAT, 0));
     661           1 :         smbcli_rename(cli->tree,
     662             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname1",
     663             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
     664           1 :         smbcli_rename(cli->tree,
     665             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
     666             :                         BASEDIR_CN1_CNMC "\\subname2-r");
     667           1 :         smbcli_rename(cli->tree,
     668             :                         BASEDIR_CN1_CNMC "\\subname2-r",
     669             :                         BASEDIR_CN1_CNMC "\\subname3-r");
     670             : 
     671           1 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
     672           1 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
     673           1 :         smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\subname3-r");
     674             : 
     675           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     676           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     677             :                                         "smb_raw_changenotify_recv");
     678             : 
     679           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     680             :                                       1, ret, done, "wrong number of changes");
     681           1 :         torture_assert_int_equal_goto(tctx,
     682             :                                       notify.nttrans.out.changes[0].action,
     683             :                                       NOTIFY_ACTION_MODIFIED, ret, done,
     684             :                                       "wrong action (exp: MODIFIED)");
     685           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname2-r",
     686             :                    STR_UNICODE);
     687             : 
     688           1 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     689           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     690             :                                         "smb_raw_changenotify_recv");
     691             : 
     692           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     693             :                                       1, ret, done, "wrong number of changes");
     694           1 :         torture_assert_int_equal_goto(tctx,
     695             :                                       notify.nttrans.out.changes[0].action,
     696             :                                       NOTIFY_ACTION_MODIFIED, ret, done,
     697             :                                       "wrong action (exp: MODIFIED)");
     698           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname3-r",
     699             :                    STR_UNICODE);
     700             : 
     701           1 : done:
     702           1 :         smb_raw_exit(cli->session);
     703           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_CNMC);
     704           1 :         return ret;
     705             : }
     706             : 
     707             : 
     708             : /* 
     709             :    testing of mask bits for change notify
     710             : */
     711             : 
     712             : #define BASEDIR_CN1_NOTM BASEDIR "_CN1_NOTM"
     713             : 
     714           1 : static bool test_notify_mask(struct torture_context *tctx,
     715             :                              struct smbcli_state *cli,
     716             :                              struct smbcli_state *cli2)
     717             : {
     718           1 :         bool ret = true;
     719             :         NTSTATUS status;
     720             :         union smb_notify notify;
     721             :         union smb_open io;
     722             :         union smb_chkpath chkpath;
     723             :         int fnum, fnum2;
     724             :         uint32_t mask;
     725             :         int i;
     726           1 :         char c = 1;
     727             :         struct timeval tv;
     728             :         NTTIME t;
     729             : 
     730           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
     731             : 
     732           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NOTM),
     733             :                        "Failed to setup up test directory: " BASEDIR_CN1_NOTM);
     734             : 
     735           1 :         tv = timeval_current_ofs(1000, 0);
     736           1 :         t = timeval_to_nttime(&tv);
     737             : 
     738             :         /*
     739             :           get a handle on the directory
     740             :         */
     741           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
     742           1 :         io.ntcreatex.in.root_fid.fnum = 0;
     743           1 :         io.ntcreatex.in.flags = 0;
     744           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
     745           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     746           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
     747           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
     748           1 :         io.ntcreatex.in.alloc_size = 0;
     749           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
     750           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
     751           1 :         io.ntcreatex.in.security_flags = 0;
     752           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_NOTM;
     753             : 
     754           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
     755           1 :         notify.nttrans.in.buffer_size = 1000;
     756           1 :         notify.nttrans.in.recursive = true;
     757             : 
     758           1 :         chkpath.chkpath.in.path = "\\";
     759             : 
     760             : #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
     761             :         do { \
     762             :         smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
     763             :         for (mask=i=0;i<32;i++) { \
     764             :                 struct smbcli_request *req; \
     765             :                 status = smb_raw_open(cli->tree, tctx, &io); \
     766             :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
     767             :                                                 "smb_raw_open"); \
     768             :                 fnum = io.ntcreatex.out.file.fnum; \
     769             :                 setup \
     770             :                 notify.nttrans.in.file.fnum = fnum;     \
     771             :                 notify.nttrans.in.completion_filter = ((uint32_t)1<<i); \
     772             :                 req = smb_raw_changenotify_send(cli->tree, &notify); \
     773             :                 smb_raw_chkpath(cli->tree, &chkpath); \
     774             :                 op \
     775             :                 smb_msleep(200); smb_raw_ntcancel(req); \
     776             :                 status = smb_raw_changenotify_recv(req, tctx, &notify); \
     777             :                 cleanup \
     778             :                 smbcli_close(cli->tree, fnum); \
     779             :                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
     780             :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
     781             :                                                 "smbcli_close"); \
     782             :                 /* special case to cope with file rename behaviour */ \
     783             :                 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
     784             :                     notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
     785             :                     ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
     786             :                     Action == NOTIFY_ACTION_OLD_NAME) { \
     787             :                         torture_comment(tctx, "(rename file special handling OK)\n"); \
     788             :                 } else { \
     789             :                         torture_assert_int_equal_goto(tctx, \
     790             :                                 notify.nttrans.out.num_changes,\
     791             :                                 nchanges, ret, done, \
     792             :                                 talloc_asprintf(tctx, \
     793             :                                         "nchanges=%d expected=%d action=%d " \
     794             :                                         "filter=0x%08x\n", \
     795             :                                         notify.nttrans.out.num_changes, \
     796             :                                         nchanges, \
     797             :                                         notify.nttrans.out.changes[0].action, \
     798             :                                         notify.nttrans.in.completion_filter)); \
     799             :                         torture_assert_int_equal_goto(tctx, \
     800             :                                 notify.nttrans.out.changes[0].action, \
     801             :                                 Action, ret, done, \
     802             :                                 talloc_asprintf(tctx, \
     803             :                                         "nchanges=%d action=%d " \
     804             :                                         "expectedAction=%d filter=0x%08x\n", \
     805             :                                         notify.nttrans.out.num_changes, \
     806             :                                         notify.nttrans.out.changes[0].action, \
     807             :                                         Action, \
     808             :                                         notify.nttrans.in.completion_filter)); \
     809             :                         torture_assert_str_equal_goto(tctx, \
     810             :                                 notify.nttrans.out.changes[0].name.s, \
     811             :                                 "tname1", ret, done, \
     812             :                                 talloc_asprintf(tctx, \
     813             :                                         "nchanges=%d action=%d filter=0x%08x " \
     814             :                                         "name=%s expected_name=tname1\n", \
     815             :                                         notify.nttrans.out.num_changes, \
     816             :                                         notify.nttrans.out.changes[0].action, \
     817             :                                         notify.nttrans.in.completion_filter, \
     818             :                                         notify.nttrans.out.changes[0].name.s));\
     819             :                 } \
     820             :                 mask |= ((uint32_t)1<<i); \
     821             :         } \
     822             :         if ((expected) != mask) { \
     823             :                 torture_assert_int_not_equal_goto(tctx, ((expected) & ~mask), \
     824             :                                 0, ret, done, "Too few bits"); \
     825             :                 torture_comment(tctx, "WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
     826             :                        mask, expected); \
     827             :         } \
     828             :         } while (0);
     829             : 
     830           1 :         torture_comment(tctx, "Testing mkdir\n");
     831           1 :         NOTIFY_MASK_TEST("Testing mkdir",;,
     832             :                          smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
     833             :                          smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
     834             :                          NOTIFY_ACTION_ADDED,
     835             :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
     836             : 
     837           1 :         torture_comment(tctx, "Testing create file\n");
     838           1 :         NOTIFY_MASK_TEST("Testing create file",;,
     839             :                          smbcli_close(cli->tree,
     840             :                                 smbcli_open(cli->tree,
     841             :                                         BASEDIR_CN1_NOTM "\\tname1",
     842             :                                         O_CREAT, 0));,
     843             :                          smbcli_unlink(cli2->tree,
     844             :                                 BASEDIR_CN1_NOTM "\\tname1");,
     845             :                          NOTIFY_ACTION_ADDED,
     846             :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
     847             : 
     848           1 :         torture_comment(tctx, "Testing unlink\n");
     849           1 :         NOTIFY_MASK_TEST("Testing unlink",
     850             :                          smbcli_close(cli->tree,
     851             :                                 smbcli_open(cli->tree,
     852             :                                         BASEDIR_CN1_NOTM "\\tname1",
     853             :                                         O_CREAT, 0));,
     854             :                          smbcli_unlink(cli2->tree,
     855             :                                 BASEDIR_CN1_NOTM "\\tname1");,
     856             :                          ;,
     857             :                          NOTIFY_ACTION_REMOVED,
     858             :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
     859             : 
     860           1 :         torture_comment(tctx, "Testing rmdir\n");
     861           1 :         NOTIFY_MASK_TEST("Testing rmdir",
     862             :                          smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
     863             :                          smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
     864             :                          ;,
     865             :                          NOTIFY_ACTION_REMOVED,
     866             :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
     867             : 
     868           1 :         torture_comment(tctx, "Testing rename file\n");
     869           1 :         NOTIFY_MASK_TEST("Testing rename file",
     870             :                          smbcli_close(cli->tree,
     871             :                                 smbcli_open(cli->tree,
     872             :                                         BASEDIR_CN1_NOTM "\\tname1",
     873             :                                         O_CREAT, 0));,
     874             :                          smbcli_rename(cli2->tree,
     875             :                                 BASEDIR_CN1_NOTM "\\tname1",
     876             :                                 BASEDIR_CN1_NOTM "\\tname2");,
     877             :                          smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
     878             :                          NOTIFY_ACTION_OLD_NAME,
     879             :                          FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
     880             : 
     881           1 :         torture_comment(tctx, "Testing rename dir\n");
     882           1 :         NOTIFY_MASK_TEST("Testing rename dir",
     883             :                 smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
     884             :                 smbcli_rename(cli2->tree,
     885             :                         BASEDIR_CN1_NOTM "\\tname1",
     886             :                         BASEDIR_CN1_NOTM "\\tname2");,
     887             :                 smbcli_rmdir(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
     888             :                 NOTIFY_ACTION_OLD_NAME,
     889             :                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
     890             : 
     891           1 :         torture_comment(tctx, "Testing set path attribute\n");
     892           1 :         NOTIFY_MASK_TEST("Testing set path attribute",
     893             :                 smbcli_close(cli->tree,
     894             :                         smbcli_open(cli->tree,
     895             :                                 BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
     896             :                 smbcli_setatr(cli2->tree,
     897             :                         BASEDIR_CN1_NOTM "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
     898             :                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
     899             :                 NOTIFY_ACTION_MODIFIED,
     900             :                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
     901             : 
     902           1 :         torture_comment(tctx, "Testing set path write time\n");
     903           1 :         NOTIFY_MASK_TEST("Testing set path write time",
     904             :                 smbcli_close(cli->tree, smbcli_open(cli->tree,
     905             :                         BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
     906             :                 smbcli_setatr(cli2->tree,
     907             :                         BASEDIR_CN1_NOTM "\\tname1",
     908             :                         FILE_ATTRIBUTE_NORMAL, 1000);,
     909             :                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
     910             :                 NOTIFY_ACTION_MODIFIED,
     911             :                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
     912             : 
     913           1 :         torture_comment(tctx, "Testing set file attribute\n");
     914           1 :         NOTIFY_MASK_TEST("Testing set file attribute",
     915             :                 fnum2 = create_complex_file(cli2, tctx,
     916             :                         BASEDIR_CN1_NOTM "\\tname1");,
     917             :                 smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
     918             :                 (smbcli_close(cli2->tree, fnum2),
     919             :                 smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
     920             :                 NOTIFY_ACTION_MODIFIED,
     921             :                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
     922             : 
     923           1 :         if (torture_setting_bool(tctx, "samba3", false)) {
     924           0 :                 torture_comment(tctx, "Samba3 does not yet support create times "
     925             :                        "everywhere\n");
     926             :         }
     927             :         else {
     928           1 :                 torture_comment(tctx, "Testing set file create time\n");
     929           1 :                 NOTIFY_MASK_TEST("Testing set file create time",
     930             :                         fnum2 = create_complex_file(cli, tctx,
     931             :                                             BASEDIR_CN1_NOTM "\\tname1");,
     932             :                         smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
     933             :                         (smbcli_close(cli->tree, fnum2),
     934             :                          smbcli_unlink(cli->tree,
     935             :                                         BASEDIR_CN1_NOTM "\\tname1"));,
     936             :                         NOTIFY_ACTION_MODIFIED,
     937             :                         FILE_NOTIFY_CHANGE_CREATION, 1);
     938             :         }
     939             : 
     940           1 :         torture_comment(tctx, "Testing set file access time\n");
     941           1 :         NOTIFY_MASK_TEST("Testing set file access time",
     942             :                 fnum2 = create_complex_file(cli, tctx,
     943             :                                 BASEDIR_CN1_NOTM "\\tname1");,
     944             :                 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
     945             :                 (smbcli_close(cli->tree, fnum2),
     946             :                         smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
     947             :                 NOTIFY_ACTION_MODIFIED,
     948             :                 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
     949             : 
     950           1 :         torture_comment(tctx, "Testing set file write time\n");
     951           1 :         NOTIFY_MASK_TEST("Testing set file write time",
     952             :                 fnum2 = create_complex_file(cli, tctx,
     953             :                         BASEDIR_CN1_NOTM "\\tname1");,
     954             :                 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
     955             :                 (smbcli_close(cli->tree, fnum2),
     956             :                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
     957             :                 NOTIFY_ACTION_MODIFIED,
     958             :                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
     959             : 
     960           1 :         torture_comment(tctx, "Testing set file change time\n");
     961           1 :         NOTIFY_MASK_TEST("Testing set file change time",
     962             :                 fnum2 = create_complex_file(cli, tctx,
     963             :                         BASEDIR_CN1_NOTM "\\tname1");,
     964             :                 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
     965             :                 (smbcli_close(cli->tree, fnum2),
     966             :                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
     967             :                 NOTIFY_ACTION_MODIFIED,
     968             :                 0, 1);
     969             : 
     970             : 
     971           1 :         torture_comment(tctx, "Testing write\n");
     972           1 :         NOTIFY_MASK_TEST("Testing write",
     973             :                 fnum2 = create_complex_file(cli2, tctx,
     974             :                         BASEDIR_CN1_NOTM "\\tname1");,
     975             :                 smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
     976             :                 (smbcli_close(cli2->tree, fnum2),
     977             :                         smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
     978             :                 NOTIFY_ACTION_MODIFIED,
     979             :                 0, 1);
     980             : 
     981           1 :         torture_comment(tctx, "Testing truncate\n");
     982           1 :         NOTIFY_MASK_TEST("Testing truncate",
     983             :                 fnum2 = create_complex_file(cli2, tctx,
     984             :                         BASEDIR_CN1_NOTM "\\tname1");,
     985             :                 smbcli_ftruncate(cli2->tree, fnum2, 10000);,
     986             :                 (smbcli_close(cli2->tree, fnum2),
     987             :                 smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
     988             :                 NOTIFY_ACTION_MODIFIED,
     989             :                 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
     990             : 
     991           2 : done:
     992           1 :         smb_raw_exit(cli->session);
     993           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NOTM);
     994           1 :         return ret;
     995             : }
     996             : 
     997             : /*
     998             :   basic testing of change notify on files
     999             : */
    1000             : 
    1001             : #define BASEDIR_CN1_FILE BASEDIR "_CN1_FILE"
    1002             : 
    1003           1 : static bool test_notify_file(struct torture_context *tctx,
    1004             :                              struct smbcli_state *cli)
    1005             : {
    1006             :         NTSTATUS status;
    1007           1 :         bool ret = true;
    1008             :         union smb_open io;
    1009             :         union smb_close cl;
    1010             :         union smb_notify notify;
    1011             :         struct smbcli_request *req;
    1012             :         int fnum;
    1013           1 :         const char *fname = BASEDIR_CN1_FILE "\\file.txt";
    1014             : 
    1015           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY ON FILES\n");
    1016             : 
    1017           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_FILE),
    1018             :                        "Failed to setup up test directory: " BASEDIR_CN1_FILE);
    1019             : 
    1020           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1021           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1022           1 :         io.ntcreatex.in.flags = 0;
    1023           1 :         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
    1024           1 :         io.ntcreatex.in.create_options = 0;
    1025           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1026           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1027           1 :         io.ntcreatex.in.alloc_size = 0;
    1028           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
    1029           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1030           1 :         io.ntcreatex.in.security_flags = 0;
    1031           1 :         io.ntcreatex.in.fname = fname;
    1032           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1033           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1034             :                                         "smb_raw_open");
    1035           1 :         fnum = io.ntcreatex.out.file.fnum;
    1036             : 
    1037             :         /* ask for a change notify,
    1038             :            on file or directory name changes */
    1039           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1040           1 :         notify.nttrans.in.file.fnum = fnum;
    1041           1 :         notify.nttrans.in.buffer_size = 1000;
    1042           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
    1043           1 :         notify.nttrans.in.recursive = false;
    1044             : 
    1045           1 :         torture_comment(tctx, "Testing if notifies on file handles are invalid (should be)\n");
    1046             : 
    1047           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1048           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1049           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
    1050             :                                            NT_STATUS_INVALID_PARAMETER,
    1051             :                                            ret, done,
    1052             :                                            "smb_raw_changenotify_recv");
    1053             : 
    1054           1 :         cl.close.level = RAW_CLOSE_CLOSE;
    1055           1 :         cl.close.in.file.fnum = fnum;
    1056           1 :         cl.close.in.write_time = 0;
    1057           1 :         status = smb_raw_close(cli->tree, &cl);
    1058           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1059             :                                         "smb_raw_close");
    1060             : 
    1061           1 :         status = smbcli_unlink(cli->tree, fname);
    1062           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1063             :                                         "smbcli_unlink");
    1064             : 
    1065           1 : done:
    1066           1 :         smb_raw_exit(cli->session);
    1067           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_FILE);
    1068           1 :         return ret;
    1069             : }
    1070             : 
    1071             : /*
    1072             :   basic testing of change notifies followed by a tdis
    1073             : */
    1074             : #define BASEDIR_CN1_TDIS BASEDIR "_CN1_TDIS"
    1075             : 
    1076           1 : static bool test_notify_tdis(struct torture_context *tctx,
    1077             :                              struct smbcli_state *cli1)
    1078             : {
    1079           1 :         bool ret = true;
    1080             :         NTSTATUS status;
    1081             :         union smb_notify notify;
    1082             :         union smb_open io;
    1083             :         int fnum;
    1084             :         struct smbcli_request *req;
    1085           1 :         struct smbcli_state *cli = NULL;
    1086             : 
    1087           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
    1088             : 
    1089           1 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TDIS),
    1090             :                        "Failed to setup up test directory: " BASEDIR_CN1_TDIS);
    1091             : 
    1092           1 :         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
    1093             :                        "Failed to open connection.");
    1094             : 
    1095             :         /*
    1096             :           get a handle on the directory
    1097             :         */
    1098           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1099           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1100           1 :         io.ntcreatex.in.flags = 0;
    1101           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1102           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1103           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1104           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1105           1 :         io.ntcreatex.in.alloc_size = 0;
    1106           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1107           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1108           1 :         io.ntcreatex.in.security_flags = 0;
    1109           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_TDIS;
    1110             : 
    1111           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1112           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1113             :                                         "smb_raw_open");
    1114           1 :         fnum = io.ntcreatex.out.file.fnum;
    1115             : 
    1116             :         /* ask for a change notify,
    1117             :            on file or directory name changes */
    1118           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1119           1 :         notify.nttrans.in.buffer_size = 1000;
    1120           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1121           1 :         notify.nttrans.in.file.fnum = fnum;
    1122           1 :         notify.nttrans.in.recursive = true;
    1123             : 
    1124           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1125             : 
    1126           1 :         status = smbcli_tdis(cli);
    1127           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1128             :                                         "smbcli_tdis");
    1129           1 :         cli->tree = NULL;
    1130             : 
    1131           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1132           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1133             :                                         "smb_raw_changenotify_recv");
    1134           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1135             :                                       0, ret, done, "no changes expected");
    1136             : 
    1137           2 : done:
    1138           1 :         torture_close_connection(cli);
    1139           1 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_TDIS);
    1140           1 :         return ret;
    1141             : }
    1142             : 
    1143             : /*
    1144             :   basic testing of change notifies followed by a exit
    1145             : */
    1146             : 
    1147             : #define BASEDIR_CN1_EX BASEDIR "_CN1_EX"
    1148             : 
    1149           1 : static bool test_notify_exit(struct torture_context *tctx,
    1150             :                              struct smbcli_state *cli1)
    1151             : {
    1152           1 :         bool ret = true;
    1153             :         NTSTATUS status;
    1154             :         union smb_notify notify;
    1155             :         union smb_open io;
    1156             :         int fnum;
    1157             :         struct smbcli_request *req;
    1158           1 :         struct smbcli_state *cli = NULL;
    1159             : 
    1160           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
    1161             : 
    1162           1 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_EX),
    1163             :                        "Failed to setup up test directory: " BASEDIR_CN1_EX);
    1164             : 
    1165           1 :         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
    1166             :                        "Failed to open connection.");
    1167             : 
    1168             :         /*
    1169             :           get a handle on the directory
    1170             :         */
    1171           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1172           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1173           1 :         io.ntcreatex.in.flags = 0;
    1174           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1175           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1176           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1177           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1178           1 :         io.ntcreatex.in.alloc_size = 0;
    1179           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1180           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1181           1 :         io.ntcreatex.in.security_flags = 0;
    1182           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_EX;
    1183             : 
    1184           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1185           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1186             :                                         "smb_raw_open");
    1187           1 :         fnum = io.ntcreatex.out.file.fnum;
    1188             : 
    1189             :         /* ask for a change notify,
    1190             :            on file or directory name changes */
    1191           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1192           1 :         notify.nttrans.in.buffer_size = 1000;
    1193           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1194           1 :         notify.nttrans.in.file.fnum = fnum;
    1195           1 :         notify.nttrans.in.recursive = true;
    1196             : 
    1197           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1198             : 
    1199           1 :         status = smb_raw_exit(cli->session);
    1200           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1201             :                                         "smb_raw_exit");
    1202             : 
    1203           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1204           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1205             :                                         "smb_raw_changenotify_recv");
    1206           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1207             :                                       0, ret, done, "no changes expected");
    1208             : 
    1209           2 : done:
    1210           1 :         torture_close_connection(cli);
    1211           1 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_EX);
    1212           1 :         return ret;
    1213             : }
    1214             : 
    1215             : /*
    1216             :   basic testing of change notifies followed by a ulogoff
    1217             : */
    1218             : 
    1219             : #define BASEDIR_CN1_UL BASEDIR "_CN1_UL"
    1220             : 
    1221           1 : static bool test_notify_ulogoff(struct torture_context *tctx,
    1222             :                                 struct smbcli_state *cli1)
    1223             : {
    1224           1 :         bool ret = true;
    1225             :         NTSTATUS status;
    1226             :         union smb_notify notify;
    1227             :         union smb_open io;
    1228             :         int fnum;
    1229             :         struct smbcli_request *req;
    1230           1 :         struct smbcli_state *cli = NULL;
    1231             : 
    1232           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
    1233             : 
    1234           1 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_UL),
    1235             :                        "Failed to setup up test directory: " BASEDIR_CN1_UL);
    1236             : 
    1237           1 :         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
    1238             :                        "Failed to open connection.");
    1239             : 
    1240             :         /*
    1241             :           get a handle on the directory
    1242             :         */
    1243           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1244           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1245           1 :         io.ntcreatex.in.flags = 0;
    1246           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1247           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1248           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1249           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1250           1 :         io.ntcreatex.in.alloc_size = 0;
    1251           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1252           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1253           1 :         io.ntcreatex.in.security_flags = 0;
    1254           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_UL;
    1255             : 
    1256           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1257           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1258             :                                         "smb_raw_open");
    1259           1 :         fnum = io.ntcreatex.out.file.fnum;
    1260             : 
    1261             :         /* ask for a change notify,
    1262             :            on file or directory name changes */
    1263           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1264           1 :         notify.nttrans.in.buffer_size = 1000;
    1265           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1266           1 :         notify.nttrans.in.file.fnum = fnum;
    1267           1 :         notify.nttrans.in.recursive = true;
    1268             : 
    1269           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1270             : 
    1271           1 :         status = smb_raw_ulogoff(cli->session);
    1272           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1273             :                                         "smb_raw_ulogoff");
    1274             : 
    1275           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1276           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1277             :                                         "smb_raw_changenotify_recv");
    1278           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1279             :                                       0, ret, done, "no changes expected");
    1280             : 
    1281           2 : done:
    1282           1 :         torture_close_connection(cli);
    1283           1 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_UL);
    1284           1 :         return ret;
    1285             : }
    1286             : 
    1287           1 : static void tcp_dis_handler(struct smbcli_transport *t, void *p)
    1288             : {
    1289           1 :         struct smbcli_state *cli = (struct smbcli_state *)p;
    1290           1 :         smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
    1291           1 :         cli->transport = NULL;
    1292           1 :         cli->tree = NULL;
    1293           1 : }
    1294             : /*
    1295             :   basic testing of change notifies followed by tcp disconnect
    1296             : */
    1297             : 
    1298             : #define BASEDIR_CN1_TCPDIS BASEDIR "_CN1_TCPDIS"
    1299             : 
    1300           1 : static bool test_notify_tcp_dis(struct torture_context *tctx,
    1301             :                                 struct smbcli_state *cli1)
    1302             : {
    1303           1 :         bool ret = true;
    1304             :         NTSTATUS status;
    1305             :         union smb_notify notify;
    1306             :         union smb_open io;
    1307             :         int fnum;
    1308             :         struct smbcli_request *req;
    1309           1 :         struct smbcli_state *cli = NULL;
    1310             : 
    1311           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
    1312             : 
    1313           1 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TCPDIS),
    1314             :                        "Failed to setup up test directory: "
    1315             :                         BASEDIR_CN1_TCPDIS);
    1316             : 
    1317           1 :         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
    1318             :                        "Failed to open connection.");
    1319             : 
    1320             :         /*
    1321             :           get a handle on the directory
    1322             :         */
    1323           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1324           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1325           1 :         io.ntcreatex.in.flags = 0;
    1326           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1327           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1328           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1329           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1330           1 :         io.ntcreatex.in.alloc_size = 0;
    1331           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1332           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1333           1 :         io.ntcreatex.in.security_flags = 0;
    1334           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_TCPDIS;
    1335             : 
    1336           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1337           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1338             :                                         "smb_raw_open");
    1339           1 :         fnum = io.ntcreatex.out.file.fnum;
    1340             : 
    1341             :         /* ask for a change notify,
    1342             :            on file or directory name changes */
    1343           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1344           1 :         notify.nttrans.in.buffer_size = 1000;
    1345           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1346           1 :         notify.nttrans.in.file.fnum = fnum;
    1347           1 :         notify.nttrans.in.recursive = true;
    1348             : 
    1349           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1350             : 
    1351           1 :         smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250000, cli);
    1352             : 
    1353           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1354           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
    1355             :                                            NT_STATUS_LOCAL_DISCONNECT,
    1356             :                                            ret, done,
    1357             :                                            "smb_raw_changenotify_recv");
    1358             : 
    1359           1 : done:
    1360           1 :         torture_close_connection(cli);
    1361           1 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_TCPDIS);
    1362           1 :         return ret;
    1363             : }
    1364             : 
    1365             : /* 
    1366             :    test setting up two change notify requests on one handle
    1367             : */
    1368             : 
    1369             : #define BASEDIR_CN1_DBL BASEDIR "_CN1_DBL"
    1370             : 
    1371           1 : static bool test_notify_double(struct torture_context *tctx,
    1372             :                                struct smbcli_state *cli)
    1373             : {
    1374           1 :         bool ret = true;
    1375             :         NTSTATUS status;
    1376             :         union smb_notify notify;
    1377             :         union smb_open io;
    1378             :         int fnum;
    1379             :         struct smbcli_request *req1, *req2;
    1380             : 
    1381           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
    1382             : 
    1383           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DBL),
    1384             :                        "Failed to setup up test directory: " BASEDIR_CN1_DBL);
    1385             : 
    1386             :         /*
    1387             :           get a handle on the directory
    1388             :         */
    1389           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1390           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1391           1 :         io.ntcreatex.in.flags = 0;
    1392           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1393           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1394           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1395           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1396           1 :         io.ntcreatex.in.alloc_size = 0;
    1397           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1398           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1399           1 :         io.ntcreatex.in.security_flags = 0;
    1400           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_DBL;
    1401             : 
    1402           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1403           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1404             :                                         "smb_raw_open");
    1405           1 :         fnum = io.ntcreatex.out.file.fnum;
    1406             : 
    1407             :         /* ask for a change notify,
    1408             :            on file or directory name changes */
    1409           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1410           1 :         notify.nttrans.in.buffer_size = 1000;
    1411           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1412           1 :         notify.nttrans.in.file.fnum = fnum;
    1413           1 :         notify.nttrans.in.recursive = true;
    1414             : 
    1415           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1416           1 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
    1417             : 
    1418           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name");
    1419             : 
    1420           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1421           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1422             :                                         "smb_raw_changenotify_recv");
    1423           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1424             :                                       1, ret, done, "wrong number of changes");
    1425           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    1426             :                    STR_UNICODE);
    1427             : 
    1428           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name2");
    1429             : 
    1430           1 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
    1431           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1432             :                                         "smb_raw_changenotify_recv");
    1433           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1434             :                                       1, ret, done, "wrong number of changes");
    1435           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name2",
    1436             :                    STR_UNICODE);
    1437             : 
    1438           1 : done:
    1439           1 :         smb_raw_exit(cli->session);
    1440           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_DBL);
    1441           1 :         return ret;
    1442             : }
    1443             : 
    1444             : 
    1445             : /* 
    1446             :    test multiple change notifies at different depths and with/without recursion
    1447             : */
    1448             : 
    1449             : #define BASEDIR_CN1_TNT BASEDIR "_CN1_TNT"
    1450             : 
    1451           1 : static bool test_notify_tree(struct torture_context *tctx,
    1452             :                              struct smbcli_state *cli,
    1453             :                              struct smbcli_state *cli2)
    1454             : {
    1455           1 :         bool ret = true;
    1456             :         union smb_notify notify;
    1457             :         union smb_open io;
    1458             :         struct smbcli_request *req;
    1459             :         struct timeval tv;
    1460             :         struct {
    1461             :                 const char *path;
    1462             :                 bool recursive;
    1463             :                 uint32_t filter;
    1464             :                 int expected;
    1465             :                 int fnum;
    1466             :                 int counted;
    1467           1 :         } dirs[] = {
    1468             :                 {
    1469             :                         .path      = BASEDIR_CN1_TNT "\\abc",
    1470             :                         .recursive = true,
    1471             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1472             :                         .expected  = 30,
    1473             :                 },
    1474             :                 {
    1475             :                         .path      = BASEDIR_CN1_TNT "\\zqy",
    1476             :                         .recursive = true,
    1477             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1478             :                         .expected  = 8,
    1479             :                 },
    1480             :                 {
    1481             :                         .path      = BASEDIR_CN1_TNT "\\atsy",
    1482             :                         .recursive = true,
    1483             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1484             :                         .expected  = 4,
    1485             :                 },
    1486             :                 {
    1487             :                         .path      = BASEDIR_CN1_TNT "\\abc\\foo",
    1488             :                         .recursive = true,
    1489             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1490             :                         .expected  = 2,
    1491             :                 },
    1492             :                 {
    1493             :                         .path      = BASEDIR_CN1_TNT "\\abc\\blah",
    1494             :                         .recursive = true,
    1495             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1496             :                         .expected  = 13,
    1497             :                 },
    1498             :                 {
    1499             :                         .path      = BASEDIR_CN1_TNT "\\abc\\blah",
    1500             :                         .recursive = false,
    1501             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1502             :                         .expected  = 7,
    1503             :                 },
    1504             :                 {
    1505             :                         .path      = BASEDIR_CN1_TNT "\\abc\\blah\\a",
    1506             :                         .recursive = true,
    1507             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1508             :                         .expected  = 2,
    1509             :                 },
    1510             :                 {
    1511             :                         .path      = BASEDIR_CN1_TNT "\\abc\\blah\\b",
    1512             :                         .recursive = true,
    1513             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1514             :                         .expected  = 2,
    1515             :                 },
    1516             :                 {
    1517             :                         .path      = BASEDIR_CN1_TNT "\\abc\\blah\\c",
    1518             :                         .recursive = true,
    1519             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1520             :                         .expected  = 2,
    1521             :                 },
    1522             :                 {
    1523             :                         .path      = BASEDIR_CN1_TNT "\\abc\\fooblah",
    1524             :                         .recursive = true,
    1525             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1526             :                         .expected  = 2,
    1527             :                 },
    1528             :                 {
    1529             :                         .path      = BASEDIR_CN1_TNT "\\zqy\\xx",
    1530             :                         .recursive = true,
    1531             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1532             :                         .expected  = 2,
    1533             :                 },
    1534             :                 {
    1535             :                         .path      = BASEDIR_CN1_TNT "\\zqy\\yyy",
    1536             :                         .recursive = true,
    1537             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1538             :                         .expected  = 2,
    1539             :                 },
    1540             :                 {
    1541             :                         .path      = BASEDIR_CN1_TNT "\\zqy\\..",
    1542             :                         .recursive = true,
    1543             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1544             :                         .expected  = 40,
    1545             :                 },
    1546             :                 {
    1547             :                         .path      = BASEDIR_CN1_TNT,
    1548             :                         .recursive = true,
    1549             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1550             :                         .expected  = 40,
    1551             :                 },
    1552             :                 {
    1553             :                         .path      = BASEDIR_CN1_TNT,
    1554             :                         .recursive = false,
    1555             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1556             :                         .expected  = 6,
    1557             :                 },
    1558             :                 {
    1559             :                         .path      = BASEDIR_CN1_TNT "\\atsy",
    1560             :                         .recursive = false,
    1561             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1562             :                         .expected  = 4,
    1563             :                 },
    1564             :                 {
    1565             :                         .path      = BASEDIR_CN1_TNT "\\abc",
    1566             :                         .recursive = true,
    1567             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1568             :                         .expected  = 24,
    1569             :                 },
    1570             :                 {
    1571             :                         .path      = BASEDIR_CN1_TNT "\\abc",
    1572             :                         .recursive = false,
    1573             :                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
    1574             :                         .expected  = 0,
    1575             :                 },
    1576             :                 {
    1577             :                         .path      = BASEDIR_CN1_TNT "\\abc",
    1578             :                         .recursive = true,
    1579             :                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
    1580             :                         .expected  = 0,
    1581             :                 },
    1582             :                 {
    1583             :                         .path      = BASEDIR_CN1_TNT "\\abc",
    1584             :                         .recursive = true,
    1585             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1586             :                         .expected  = 24,
    1587             :                 },
    1588             :         };
    1589             :         int i;
    1590             :         NTSTATUS status;
    1591           1 :         bool all_done = false;
    1592             : 
    1593           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
    1594             : 
    1595           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_TNT),
    1596             :                        "Failed to setup up test directory: " BASEDIR_CN1_TNT);
    1597             : 
    1598           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1599           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1600           1 :         io.ntcreatex.in.flags = 0;
    1601           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1602           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1603           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1604           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1605           1 :         io.ntcreatex.in.alloc_size = 0;
    1606           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
    1607           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1608           1 :         io.ntcreatex.in.security_flags = 0;
    1609             : 
    1610           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1611           1 :         notify.nttrans.in.buffer_size = 20000;
    1612             : 
    1613             :         /*
    1614             :           setup the directory tree, and the notify buffer on each directory
    1615             :         */
    1616          21 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1617          20 :                 io.ntcreatex.in.fname = dirs[i].path;
    1618          20 :                 status = smb_raw_open(cli->tree, tctx, &io);
    1619          20 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1620             :                                                 "smb_raw_open");
    1621          20 :                 dirs[i].fnum = io.ntcreatex.out.file.fnum;
    1622             : 
    1623          20 :                 notify.nttrans.in.completion_filter = dirs[i].filter;
    1624          20 :                 notify.nttrans.in.file.fnum = dirs[i].fnum;
    1625          20 :                 notify.nttrans.in.recursive = dirs[i].recursive;
    1626          20 :                 req = smb_raw_changenotify_send(cli->tree, &notify);
    1627          20 :                 smb_raw_ntcancel(req);
    1628          20 :                 status = smb_raw_changenotify_recv(req, tctx, &notify);
    1629          20 :                 torture_assert_ntstatus_equal_goto(tctx, status,
    1630             :                                                    NT_STATUS_CANCELLED,
    1631             :                                                    ret, done,
    1632             :                                                    "smb_raw_changenotify_recv");
    1633             :         }
    1634             : 
    1635             :         /* trigger 2 events in each dir */
    1636          21 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1637          20 :                 char *path = talloc_asprintf(tctx, "%s\\test.dir", dirs[i].path);
    1638             :                 /*
    1639             :                  * Make notifies a bit more interesting in a cluster
    1640             :                  * by doing the changes against different nodes with
    1641             :                  * --unclist
    1642             :                  */
    1643          20 :                 smbcli_mkdir(cli->tree, path);
    1644          20 :                 smbcli_rmdir(cli2->tree, path);
    1645          20 :                 talloc_free(path);
    1646             :         }
    1647             : 
    1648             :         /* give a bit of time for the events to propagate */
    1649           1 :         tv = timeval_current();
    1650             : 
    1651             :         do {
    1652             :                 /* count events that have happened in each dir */
    1653          21 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1654          20 :                         notify.nttrans.in.file.fnum = dirs[i].fnum;
    1655          20 :                         req = smb_raw_changenotify_send(cli->tree, &notify);
    1656          20 :                         smb_raw_ntcancel(req);
    1657          20 :                         notify.nttrans.out.num_changes = 0;
    1658          20 :                         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1659          20 :                         dirs[i].counted += notify.nttrans.out.num_changes;
    1660             :                 }
    1661             :                 
    1662           1 :                 all_done = true;
    1663             : 
    1664          21 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1665          20 :                         if (dirs[i].counted != dirs[i].expected) {
    1666           0 :                                 all_done = false;
    1667             :                         }
    1668             :                 }
    1669           1 :         } while (!all_done && timeval_elapsed(&tv) < 20);
    1670             : 
    1671           1 :         torture_comment(tctx, "took %.4f seconds to propagate all events\n", timeval_elapsed(&tv));
    1672             : 
    1673          21 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1674          20 :                 torture_assert_int_equal_goto(tctx,
    1675             :                         dirs[i].counted, dirs[i].expected, ret, done,
    1676             :                         talloc_asprintf(tctx,
    1677             :                                         "unexpected number of events for '%s'",
    1678             :                                         dirs[i].path));
    1679             :         }
    1680             : 
    1681             :         /*
    1682             :           run from the back, closing and deleting
    1683             :         */
    1684          21 :         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
    1685          20 :                 smbcli_close(cli->tree, dirs[i].fnum);
    1686          20 :                 smbcli_rmdir(cli->tree, dirs[i].path);
    1687             :         }
    1688             : 
    1689           1 : done:
    1690           1 :         smb_raw_exit(cli->session);
    1691           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_TNT);
    1692           1 :         return ret;
    1693             : }
    1694             : 
    1695             : /*
    1696             :    Test response when cached server events exceed single NT NOTFIY response
    1697             :    packet size.
    1698             : */
    1699             : 
    1700             : #define BASEDIR_CN1_NO BASEDIR "_CN1_NO"
    1701             : 
    1702           1 : static bool test_notify_overflow(struct torture_context *tctx,
    1703             :                                  struct smbcli_state *cli)
    1704             : {
    1705           1 :         bool ret = true;
    1706             :         NTSTATUS status;
    1707             :         union smb_notify notify;
    1708             :         union smb_open io;
    1709             :         int fnum;
    1710           1 :         int count = 100;
    1711             :         struct smbcli_request *req1;
    1712             :         int i;
    1713             : 
    1714           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
    1715             : 
    1716           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NO),
    1717             :                        "Failed to setup up test directory: " BASEDIR_CN1_NO);
    1718             : 
    1719             :         /* get a handle on the directory */
    1720           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1721           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1722           1 :         io.ntcreatex.in.flags = 0;
    1723           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1724           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1725           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1726           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1727             :             NTCREATEX_SHARE_ACCESS_WRITE;
    1728           1 :         io.ntcreatex.in.alloc_size = 0;
    1729           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1730           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1731           1 :         io.ntcreatex.in.security_flags = 0;
    1732           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_NO;
    1733             : 
    1734           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1735           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1736             :                                         "smb_raw_open");
    1737           1 :         fnum = io.ntcreatex.out.file.fnum;
    1738             : 
    1739             :         /* ask for a change notify, on name changes. */
    1740           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1741           1 :         notify.nttrans.in.buffer_size = 1000;
    1742           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1743           1 :         notify.nttrans.in.file.fnum = fnum;
    1744             : 
    1745           1 :         notify.nttrans.in.recursive = true;
    1746           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1747             : 
    1748             :         /* cancel initial requests so the buffer is setup */
    1749           1 :         smb_raw_ntcancel(req1);
    1750           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1751           1 :         torture_assert_ntstatus_equal_goto(tctx, status,
    1752             :                                            NT_STATUS_CANCELLED,
    1753             :                                            ret, done,
    1754             :                                            "smb_raw_changenotify_recv");
    1755             : 
    1756             :         /* open a lot of files, filling up the server side notify buffer */
    1757           1 :         torture_comment(tctx, "Testing overflowed buffer notify on create of %d files\n",
    1758             :                count);
    1759         101 :         for (i=0;i<count;i++) {
    1760         100 :                 char *fname = talloc_asprintf(cli,
    1761             :                                 BASEDIR_CN1_NO "\\test%d.txt", i);
    1762         100 :                 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
    1763             :                                         DENY_NONE);
    1764         100 :                 torture_assert_int_not_equal_goto(tctx, fnum2, -1, ret, done,
    1765             :                         talloc_asprintf(tctx, "Failed to create %s - %s",
    1766             :                                         fname, smbcli_errstr(cli->tree)));
    1767         100 :                 talloc_free(fname);
    1768         100 :                 smbcli_close(cli->tree, fnum2);
    1769             :         }
    1770             : 
    1771             :         /* expect that 0 events will be returned with NT_STATUS_OK */
    1772           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1773           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1774           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1775             :                                         "smb_raw_changenotify_recv");
    1776           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1777             :                                       0, ret, done, "no changes expected");
    1778             : 
    1779           2 : done:
    1780           1 :         smb_raw_exit(cli->session);
    1781           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NO);
    1782           1 :         return ret;
    1783             : }
    1784             : 
    1785             : /*
    1786             :    Test if notifications are returned for changes to the base directory.
    1787             :    They shouldn't be.
    1788             : */
    1789             : 
    1790             : #define BASEDIR_CN1_NBASE BASEDIR "_CN1_NBASE"
    1791             : 
    1792           1 : static bool test_notify_basedir(struct torture_context *tctx,
    1793             :                                 struct smbcli_state *cli)
    1794             : {
    1795           1 :         bool ret = true;
    1796             :         NTSTATUS status;
    1797             :         union smb_notify notify;
    1798             :         union smb_open io;
    1799             :         int fnum;
    1800             :         struct smbcli_request *req1;
    1801             : 
    1802           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
    1803             : 
    1804           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NBASE),
    1805             :                        "Failed to setup up test directory: " BASEDIR_CN1_NBASE);
    1806             : 
    1807             :         /* get a handle on the directory */
    1808           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1809           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1810           1 :         io.ntcreatex.in.flags = 0;
    1811           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1812           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1813           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1814           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1815             :             NTCREATEX_SHARE_ACCESS_WRITE;
    1816           1 :         io.ntcreatex.in.alloc_size = 0;
    1817           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1818           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1819           1 :         io.ntcreatex.in.security_flags = 0;
    1820           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_NBASE;
    1821             : 
    1822           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1823           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1824             :                                         "smb_raw_open");
    1825           1 :         fnum = io.ntcreatex.out.file.fnum;
    1826             : 
    1827             :         /* create a test file that will also be modified */
    1828           1 :         smbcli_close(cli->tree, smbcli_open(cli->tree,
    1829             :                                 BASEDIR_CN1_NBASE "\\tname1",
    1830             :                                             O_CREAT, 0));
    1831             : 
    1832             :         /* ask for a change notify, on attribute changes. */
    1833           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1834           1 :         notify.nttrans.in.buffer_size = 1000;
    1835           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
    1836           1 :         notify.nttrans.in.file.fnum = fnum;
    1837           1 :         notify.nttrans.in.recursive = true;
    1838             : 
    1839           1 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1840             : 
    1841             :         /* set attribute on the base dir */
    1842           1 :         smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE, FILE_ATTRIBUTE_HIDDEN, 0);
    1843             : 
    1844             :         /* set attribute on a file to assure we receive a notification */
    1845           1 :         smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE "\\tname1",
    1846             :                         FILE_ATTRIBUTE_HIDDEN, 0);
    1847           1 :         smb_msleep(200);
    1848             : 
    1849             :         /* check how many responses were given, expect only 1 for the file */
    1850           1 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1851           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1852             :                                         "smb_raw_changenotify_recv");
    1853           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1854             :                                       1, ret, done, "wrong number of  changes");
    1855           1 :         torture_assert_int_equal_goto(tctx,
    1856             :                                       notify.nttrans.out.changes[0].action,
    1857             :                                       NOTIFY_ACTION_MODIFIED, ret, done,
    1858             :                                       "wrong action (exp: MODIFIED)");
    1859           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
    1860             :                    STR_UNICODE);
    1861             : 
    1862           1 : done:
    1863           1 :         smb_raw_exit(cli->session);
    1864           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NBASE);
    1865           1 :         return ret;
    1866             : }
    1867             : 
    1868             : 
    1869             : /*
    1870             :   create a secondary tree connect - used to test for a bug in Samba3 messaging
    1871             :   with change notify
    1872             : */
    1873             : 
    1874           1 : static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli, 
    1875             :                                           struct torture_context *tctx)
    1876             : {
    1877             :         NTSTATUS status;
    1878             :         const char *share, *host;
    1879             :         struct smbcli_tree *tree;
    1880             :         union smb_tcon tcon;
    1881             : 
    1882           1 :         share = torture_setting_string(tctx, "share", NULL);
    1883           1 :         host  = torture_setting_string(tctx, "host", NULL);
    1884             :         
    1885           1 :         torture_comment(tctx, "create a second tree context on the same session\n");
    1886           1 :         tree = smbcli_tree_init(cli->session, tctx, false);
    1887             : 
    1888           1 :         tcon.generic.level = RAW_TCON_TCONX;
    1889           1 :         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
    1890           1 :         tcon.tconx.in.password = data_blob(NULL, 0);
    1891           1 :         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
    1892           1 :         tcon.tconx.in.device = "A:";  
    1893           1 :         status = smb_raw_tcon(tree, tctx, &tcon);
    1894           1 :         if (!NT_STATUS_IS_OK(status)) {
    1895           0 :                 talloc_free(tree);
    1896           0 :                 torture_comment(tctx, "Failed to create secondary tree\n");
    1897           0 :                 return NULL;
    1898             :         }
    1899             : 
    1900           1 :         tree->tid = tcon.tconx.out.tid;
    1901           1 :         torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
    1902             : 
    1903           1 :         return tree;
    1904             : }
    1905             : 
    1906             : 
    1907             : /* 
    1908             :    very simple change notify test
    1909             : */
    1910             : 
    1911             : #define BASEDIR_CN1_NTCON BASEDIR "_CN1_NTCON"
    1912             : 
    1913           1 : static bool test_notify_tcon(struct torture_context *tctx,
    1914             :                              struct smbcli_state *cli)
    1915             : {
    1916           1 :         bool ret = true;
    1917             :         NTSTATUS status;
    1918             :         union smb_notify notify;
    1919             :         union smb_open io;
    1920             :         int fnum;
    1921             :         struct smbcli_request *req;
    1922             :         extern int torture_numops;
    1923           1 :         struct smbcli_tree *tree = NULL;
    1924             :                 
    1925           1 :         torture_comment(tctx, "TESTING SIMPLE CHANGE NOTIFY\n");
    1926             : 
    1927           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NTCON),
    1928             :                        "Failed to setup up test directory: " BASEDIR_CN1_NTCON);
    1929             : 
    1930             :         /*
    1931             :           get a handle on the directory
    1932             :         */
    1933           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1934           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    1935           1 :         io.ntcreatex.in.flags = 0;
    1936           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1937           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1938           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1939           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1940           1 :         io.ntcreatex.in.alloc_size = 0;
    1941           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1942           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1943           1 :         io.ntcreatex.in.security_flags = 0;
    1944           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_NTCON;
    1945             : 
    1946           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1947           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1948             :                                         "smb_raw_open");
    1949           1 :         fnum = io.ntcreatex.out.file.fnum;
    1950             : 
    1951           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    1952           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1953             :                                         "smb_raw_open");
    1954             : 
    1955             :         /* ask for a change notify,
    1956             :            on file or directory name changes */
    1957           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1958           1 :         notify.nttrans.in.buffer_size = 1000;
    1959           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1960           1 :         notify.nttrans.in.file.fnum = fnum;
    1961           1 :         notify.nttrans.in.recursive = true;
    1962             : 
    1963           1 :         torture_comment(tctx, "Testing notify mkdir\n");
    1964           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1965           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    1966             : 
    1967           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1968           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1969             :                                         "smb_raw_changenotify_recv");
    1970             : 
    1971           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1972             :                                       1, ret, done, "wrong number of changes");
    1973           1 :         torture_assert_int_equal_goto(tctx,
    1974             :                                       notify.nttrans.out.changes[0].action,
    1975             :                                       NOTIFY_ACTION_ADDED, ret, done,
    1976             :                                       "wrong action (exp: ADDED)");
    1977           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    1978             :                    STR_UNICODE);
    1979             : 
    1980           1 :         torture_comment(tctx, "Testing notify rmdir\n");
    1981           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1982           1 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    1983             : 
    1984           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1985           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1986             :                                         "smb_raw_changenotify_recv");
    1987           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1988             :                                       1, ret, done, "wrong number of changes");
    1989           1 :         torture_assert_int_equal_goto(tctx,
    1990             :                                       notify.nttrans.out.changes[0].action,
    1991             :                                       NOTIFY_ACTION_REMOVED, ret, done,
    1992             :                                       "wrong action (exp: REMOVED)");
    1993           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    1994             :                    STR_UNICODE);
    1995             : 
    1996           1 :         torture_comment(tctx, "SIMPLE CHANGE NOTIFY OK\n");
    1997             : 
    1998           1 :         torture_comment(tctx, "TESTING WITH SECONDARY TCON\n");
    1999           1 :         tree = secondary_tcon(cli, tctx);
    2000           1 :         torture_assert_not_null_goto(tctx, tree, ret, done,
    2001             :                                      "failed to create secondary tcon");
    2002             : 
    2003           1 :         torture_comment(tctx, "Testing notify mkdir\n");
    2004           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2005           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2006             : 
    2007           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2008           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2009             :                                         "smb_raw_changenotify_recv");
    2010             : 
    2011           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2012             :                                       1, ret, done, "wrong number of changes");
    2013           1 :         torture_assert_int_equal_goto(tctx,
    2014             :                                       notify.nttrans.out.changes[0].action,
    2015             :                                       NOTIFY_ACTION_ADDED, ret, done,
    2016             :                                       "wrong action (exp: ADDED)");
    2017           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2018             :                    STR_UNICODE);
    2019             : 
    2020           1 :         torture_comment(tctx, "Testing notify rmdir\n");
    2021           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2022           1 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2023             : 
    2024           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2025           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2026             :                                         "smb_raw_changenotify_recv");
    2027           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2028             :                                       1, ret, done, "wrong number of changes");
    2029           1 :         torture_assert_int_equal_goto(tctx,
    2030             :                                       notify.nttrans.out.changes[0].action,
    2031             :                                       NOTIFY_ACTION_REMOVED, ret, done,
    2032             :                                       "wrong action (exp: REMOVED)");
    2033           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2034             :                    STR_UNICODE);
    2035             : 
    2036           1 :         torture_comment(tctx, "CHANGE NOTIFY WITH TCON OK\n");
    2037             : 
    2038           1 :         torture_comment(tctx, "Disconnecting secondary tree\n");
    2039           1 :         status = smb_tree_disconnect(tree);
    2040           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2041             :                                         "smb_tree_disconnect");
    2042           1 :         talloc_free(tree);
    2043             : 
    2044           1 :         torture_comment(tctx, "Testing notify mkdir\n");
    2045           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2046           1 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2047             : 
    2048           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2049           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2050             :                                         "smb_raw_changenotify_recv");
    2051             : 
    2052           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2053             :                                       1, ret, done, "wrong number of changes");
    2054           1 :         torture_assert_int_equal_goto(tctx,
    2055             :                                       notify.nttrans.out.changes[0].action,
    2056             :                                       NOTIFY_ACTION_ADDED, ret, done,
    2057             :                                       "wrong action (exp: ADDED)");
    2058           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2059             :                    STR_UNICODE);
    2060             : 
    2061           1 :         torture_comment(tctx, "Testing notify rmdir\n");
    2062           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2063           1 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2064             : 
    2065           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2066           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2067             :                                         "smb_raw_changenotify_recv");
    2068           1 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2069             :                                       1, ret, done, "wrong number of changes");
    2070           1 :         torture_assert_int_equal_goto(tctx,
    2071             :                                       notify.nttrans.out.changes[0].action,
    2072             :                                       NOTIFY_ACTION_REMOVED, ret, done,
    2073             :                                       "wrong action (exp: REMOVED)");
    2074           1 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2075             :                    STR_UNICODE);
    2076             : 
    2077           1 :         torture_comment(tctx, "CHANGE NOTIFY WITH TDIS OK\n");
    2078           1 : done:
    2079           1 :         smb_raw_exit(cli->session);
    2080           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NTCON);
    2081           1 :         return ret;
    2082             : }
    2083             : 
    2084             : struct cb_data {
    2085             :         struct smbcli_request *req;
    2086             :         bool timed_out;
    2087             : };
    2088             : 
    2089           0 : static void timeout_cb(struct tevent_context *ev,
    2090             :                         struct tevent_timer *te,
    2091             :                         struct timeval current_time,
    2092             :                         void *private_data)
    2093             : {
    2094           0 :         struct cb_data *cbp = (struct cb_data *)private_data;
    2095           0 :         cbp->req->state = SMBCLI_REQUEST_ERROR;
    2096           0 :         cbp->timed_out = true;
    2097           0 : }
    2098             : 
    2099             : /*
    2100             :    testing alignment of multiple change notify infos
    2101             : */
    2102             : 
    2103             : #define BASEDIR_CN1_NALIGN BASEDIR "_CN1_NALIGN"
    2104             : 
    2105           1 : static bool test_notify_alignment(struct torture_context *tctx,
    2106             :                                   struct smbcli_state *cli)
    2107             : {
    2108             :         NTSTATUS status;
    2109             :         union smb_notify notify;
    2110             :         union smb_open io;
    2111             :         int fnum, fnum2;
    2112             :         struct smbcli_request *req;
    2113           1 :         const char *fname = BASEDIR_CN1_NALIGN "\\starter";
    2114           1 :         const char *fnames[] = { "a",
    2115             :                                  "ab",
    2116             :                                  "abc",
    2117             :                                  "abcd" };
    2118           1 :         bool fnames_received[] = {false,
    2119             :                                   false,
    2120             :                                   false,
    2121             :                                   false};
    2122           1 :         size_t total_names_received = 0;
    2123           1 :         size_t num_names = ARRAY_SIZE(fnames);
    2124             :         size_t i;
    2125           1 :         char *fpath = NULL;
    2126             : 
    2127           1 :         torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
    2128             : 
    2129           1 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NALIGN),
    2130             :                 "Failed to setup up test directory: " BASEDIR_CN1_NALIGN);
    2131             : 
    2132             :         /* get a handle on the directory */
    2133           1 :         io.generic.level = RAW_OPEN_NTCREATEX;
    2134           1 :         io.ntcreatex.in.root_fid.fnum = 0;
    2135           1 :         io.ntcreatex.in.flags = 0;
    2136           1 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    2137           1 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2138           1 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    2139           1 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2140             :                                        NTCREATEX_SHARE_ACCESS_WRITE;
    2141           1 :         io.ntcreatex.in.alloc_size = 0;
    2142           1 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    2143           1 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    2144           1 :         io.ntcreatex.in.security_flags = 0;
    2145           1 :         io.ntcreatex.in.fname = BASEDIR_CN1_NALIGN;
    2146             : 
    2147           1 :         status = smb_raw_open(cli->tree, tctx, &io);
    2148           1 :         torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
    2149           1 :         fnum = io.ntcreatex.out.file.fnum;
    2150             : 
    2151             :         /* ask for a change notify, on file creation */
    2152           1 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    2153           1 :         notify.nttrans.in.buffer_size = 1000;
    2154           1 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
    2155           1 :         notify.nttrans.in.file.fnum = fnum;
    2156           1 :         notify.nttrans.in.recursive = false;
    2157             : 
    2158             :         /* start change tracking */
    2159           1 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2160             : 
    2161           1 :         fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
    2162           1 :         torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
    2163           1 :         smbcli_close(cli->tree, fnum2);
    2164             : 
    2165           1 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2166           1 :         torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
    2167             : 
    2168             :         /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
    2169             :          * to be returned in the same packet with all possible 4-byte padding
    2170             :          * permutations.  As per MS-CIFS 2.2.7.4.2 these structures should be
    2171             :          * 4-byte aligned. */
    2172             : 
    2173           5 :         for (i = 0; i < num_names; i++) {
    2174           4 :                 fpath = talloc_asprintf(tctx, "%s\\%s",
    2175             :                                 BASEDIR_CN1_NALIGN, fnames[i]);
    2176           4 :                 fnum2 = smbcli_open(cli->tree, fpath,
    2177             :                     O_CREAT|O_RDWR, DENY_NONE);
    2178           4 :                 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
    2179           4 :                 smbcli_close(cli->tree, fnum2);
    2180           4 :                 talloc_free(fpath);
    2181             :         }
    2182             : 
    2183             :         /*
    2184             :          * Slow cloud filesystems mean we might
    2185             :          * not get everything in one go. Keep going
    2186             :          * until we get them all.
    2187             :          */
    2188           3 :         while (total_names_received < num_names) {
    2189           1 :                 struct tevent_timer *te = NULL;
    2190           1 :                 struct cb_data to_data = {0};
    2191             : 
    2192             :                 /*
    2193             :                  * We send a notify packet, and let
    2194             :                  * smb_raw_changenotify_recv() do
    2195             :                  * the alignment checking for us.
    2196             :                  */
    2197           1 :                 req = smb_raw_changenotify_send(cli->tree, &notify);
    2198           1 :                 torture_assert(tctx,
    2199             :                         req != NULL,
    2200             :                         "smb_raw_changenotify_send failed\n");
    2201             : 
    2202             :                 /* Ensure we don't wait more than 30 seconds. */
    2203           1 :                 to_data.req = req;
    2204           1 :                 to_data.timed_out = false;
    2205             : 
    2206           1 :                 te = tevent_add_timer(tctx->ev,
    2207             :                                 req,
    2208             :                                 tevent_timeval_current_ofs(30, 0),
    2209             :                                 timeout_cb,
    2210             :                                 &to_data);
    2211           1 :                 if (te == NULL) {
    2212           0 :                         torture_fail(tctx, "tevent_add_timer fail\n");
    2213             :                 }
    2214             : 
    2215           1 :                 status = smb_raw_changenotify_recv(req, tctx, &notify);
    2216           1 :                 if (!NT_STATUS_IS_OK(status)) {
    2217           0 :                         if (to_data.timed_out == true) {
    2218           0 :                                 torture_fail(tctx, "smb_raw_changenotify_recv "
    2219             :                                         "timed out\n");
    2220             :                         }
    2221             :                 }
    2222             : 
    2223           1 :                 torture_assert_ntstatus_ok(tctx, status,
    2224             :                         "smb_raw_changenotify_recv");
    2225             : 
    2226           5 :                 for (i = 0; i < notify.nttrans.out.num_changes; i++) {
    2227             :                         size_t j;
    2228             : 
    2229             :                         /* Ensure it was an 'add'. */
    2230           4 :                         torture_assert(tctx,
    2231             :                                 notify.nttrans.out.changes[i].action ==
    2232             :                                         NOTIFY_ACTION_ADDED,
    2233             :                                 "");
    2234             : 
    2235          10 :                         for (j = 0; j < num_names; j++) {
    2236          10 :                                 if (strcmp(notify.nttrans.out.changes[i].name.s,
    2237             :                                                 fnames[j]) == 0) {
    2238           4 :                                         if (fnames_received[j] == true) {
    2239           0 :                                                 const char *err =
    2240           0 :                                                         talloc_asprintf(tctx,
    2241             :                                                                 "Duplicate "
    2242             :                                                                 "name %s\n",
    2243             :                                                                 fnames[j]);
    2244           0 :                                                 if (err == NULL) {
    2245           0 :                                                         torture_fail(tctx,
    2246             :                                                                 "talloc "
    2247             :                                                                 "fail\n");
    2248             :                                                 }
    2249             :                                                 /* already got this. */
    2250           0 :                                                 torture_fail(tctx, err);
    2251             :                                         }
    2252           4 :                                         fnames_received[j] = true;
    2253           4 :                                         break;
    2254             :                                 }
    2255             :                         }
    2256           4 :                         if (j == num_names) {
    2257             :                                 /* No name match. */
    2258           0 :                                 const char *err = talloc_asprintf(tctx,
    2259             :                                         "Unexpected name %s\n",
    2260           0 :                                         notify.nttrans.out.changes[i].name.s);
    2261           0 :                                 if (err == NULL) {
    2262           0 :                                         torture_fail(tctx, "talloc fail\n");
    2263             :                                 }
    2264           0 :                                 torture_fail(tctx, err);
    2265             :                         }
    2266           4 :                         total_names_received++;
    2267             :                 }
    2268             :         }
    2269             : 
    2270           1 :         smb_raw_exit(cli->session);
    2271           1 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NALIGN);
    2272           1 :         return true;
    2273             : }
    2274             : 
    2275         964 : struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
    2276             : {
    2277         964 :         struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
    2278             : 
    2279         964 :         torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
    2280         964 :         torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
    2281         964 :         torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
    2282         964 :         torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
    2283         964 :         torture_suite_add_1smb_test(suite, "mask_change",
    2284             :                                     test_notify_mask_change);
    2285         964 :         torture_suite_add_1smb_test(suite, "file", test_notify_file);
    2286         964 :         torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
    2287         964 :         torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
    2288         964 :         torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
    2289         964 :         torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
    2290         964 :         torture_suite_add_1smb_test(suite, "double", test_notify_double);
    2291         964 :         torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
    2292         964 :         torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
    2293         964 :         torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
    2294         964 :         torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);
    2295             : 
    2296         964 :         return suite;
    2297             : }

Generated by: LCOV version 1.13