LCOV - code coverage report
Current view: top level - source4/torture/raw - notify.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 916 1050 87.2 %
Date: 2024-02-28 12:06:22 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           3 : static bool test_notify_dir(struct torture_context *tctx,
      45             :                             struct smbcli_state *cli,
      46             :                             struct smbcli_state *cli2)
      47             : {
      48           3 :         bool ret = true;
      49           0 :         NTSTATUS status;
      50           0 :         union smb_notify notify;
      51           0 :         union smb_open io;
      52           0 :         union smb_close cl;
      53           0 :         int i, count, fnum, fnum2;
      54           0 :         struct smbcli_request *req, *req2;
      55           0 :         extern int torture_numops;
      56             : 
      57           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
      58             : 
      59           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
      66           3 :         io.ntcreatex.in.root_fid.fnum = 0;
      67           3 :         io.ntcreatex.in.flags = 0;
      68           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
      69           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
      70           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
      71           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
      72           3 :         io.ntcreatex.in.alloc_size = 0;
      73           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
      74           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
      75           3 :         io.ntcreatex.in.security_flags = 0;
      76           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_DIR;
      77             : 
      78           3 :         status = smb_raw_open(cli->tree, tctx, &io);
      79           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      80             :                                         "smb_raw_open");
      81           3 :         fnum = io.ntcreatex.out.file.fnum;
      82             : 
      83           3 :         status = smb_raw_open(cli->tree, tctx, &io);
      84           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      85             :                                         "smb_raw_open");
      86           3 :         fnum2 = io.ntcreatex.out.file.fnum;
      87             : 
      88             :         /* ask for a change notify,
      89             :            on file or directory name changes */
      90           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
      91           3 :         notify.nttrans.in.buffer_size = 1000;
      92           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
      93           3 :         notify.nttrans.in.file.fnum = fnum;
      94           3 :         notify.nttrans.in.recursive = true;
      95             : 
      96           3 :         torture_comment(tctx, "Testing notify cancel\n");
      97             : 
      98           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
      99           3 :         smb_raw_ntcancel(req);
     100           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     101           3 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED,
     102             :                                            ret, done,
     103             :                                            "smb_raw_changenotify_recv");
     104             : 
     105           3 :         torture_comment(tctx, "Testing notify mkdir\n");
     106             : 
     107           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     108           3 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     109             : 
     110           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     111           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     112             :                                         "smb_raw_changenotify_recv");
     113             : 
     114           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     115             :                                       1, ret, done, "more than one change");
     116           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     121             :                    STR_UNICODE);
     122             : 
     123           3 :         torture_comment(tctx, "Testing notify rmdir\n");
     124             : 
     125           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     126           3 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     127             : 
     128           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     129           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     130             :                                         "smb_raw_changenotify_recv");
     131           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     132             :                                       1, ret, done, "more than one change");
     133           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     138             :                    STR_UNICODE);
     139             : 
     140           3 :         torture_comment(tctx, "Testing notify mkdir - rmdir - mkdir - rmdir\n");
     141             : 
     142           3 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     143           3 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     144           3 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     145           3 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
     146           3 :         smb_msleep(200);
     147           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     148           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     149           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     150             :                                         "smb_raw_changenotify_recv");
     151           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     152             :                                       4, ret, done, "wrong number of changes");
     153           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     158             :                    STR_UNICODE);
     159           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
     164             :                    STR_UNICODE);
     165           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subdir-name",
     170             :                    STR_UNICODE);
     171           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name, "subdir-name",
     176             :                    STR_UNICODE);
     177             : 
     178           3 :         count = torture_numops;
     179           3 :         torture_comment(tctx, "Testing buffered notify on create of %d files\n", count);
     180          33 :         for (i=0;i<count;i++) {
     181          30 :                 char *fname = talloc_asprintf(cli,
     182             :                                 BASEDIR_CN1_DIR "\\test%d.txt",
     183             :                                 i);
     184          30 :                 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
     185          30 :                 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          30 :                 talloc_free(fname);
     189          30 :                 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           3 :         notify.nttrans.in.file.fnum = fnum2;
     195           3 :         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           3 :         notify.nttrans.in.file.fnum = fnum;
     200           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     201             : 
     202           3 :         status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
     203           3 :         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           3 :         torture_comment(tctx, "Testing notify on unlink for the first file\n");
     212           3 :         status = smbcli_unlink(cli2->tree, BASEDIR_CN1_DIR "\\test0.txt");
     213           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     214             :                                         "smbcli_unlink");
     215             : 
     216             :         /* receive the reply from the 2nd notify */
     217           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     218           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     219             :                                         "smb_raw_changenotify_recv");
     220             : 
     221           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     222             :                                       count, ret, done,
     223             :                                       "wrong number of changes");
     224          30 :         for (i=1;i<count;i++) {
     225          27 :                 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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
     231             :                    STR_UNICODE);
     232             : 
     233           3 :         torture_comment(tctx, "and now from the 1st notify\n");
     234           3 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     235           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     236             :                                         "smb_raw_changenotify_recv");
     237           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     238             :                                       1, ret, done, "wrong number of changes");
     239           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
     244             :                    STR_UNICODE);
     245             : 
     246           3 :         torture_comment(tctx, "(3rd notify) this notify will only see the 1st unlink\n");
     247           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     248             : 
     249           3 :         status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
     250           3 :         torture_assert_ntstatus_equal_goto(tctx, status,
     251             :                                            NT_STATUS_OBJECT_NAME_NOT_FOUND,
     252             :                                            ret, done,
     253             :                                            "smbcli_unlink");
     254             : 
     255           3 :         torture_comment(tctx, "Testing notify on wildcard unlink for %d files\n", count-1);
     256             :         /* (2nd unlink) do a wildcard unlink */
     257           3 :         status = smbcli_unlink_wcard(cli2->tree, BASEDIR_CN1_DIR "\\test*.txt");
     258           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     259             :                                         "smb_raw_changenotify_recv");
     260             : 
     261             :         /* receive the 3rd notify */
     262           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     263           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     264             :                                         "smb_raw_changenotify_recv");
     265           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     266             :                                       1, ret, done, "wrong number of changes");
     267           3 :         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           3 :         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           3 :         notify.nttrans.in.file.fnum = fnum;
     276           3 :         sleep(3);
     277           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     278           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     279           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     280             :                                         "smb_raw_changenotify_recv");
     281           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     282             :                                       count - 1, ret, done,
     283             :                                       "wrong number of changes");
     284          30 :         for (i=0;i<notify.nttrans.out.num_changes;i++) {
     285          27 :                 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           3 :         notify.nttrans.in.file.fnum = fnum2;
     291           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     292           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     293           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     294             :                                         "smb_raw_changenotify_recv");
     295           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     296             :                                       count - 1, ret, done,
     297             :                                       "wrong number of changes");
     298          30 :         for (i=0;i<notify.nttrans.out.num_changes;i++) {
     299          27 :                 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           3 :         torture_comment(tctx, "Testing if a close() on the dir handle triggers the notify reply\n");
     306             : 
     307           3 :         notify.nttrans.in.file.fnum = fnum;
     308           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
     309             : 
     310           3 :         cl.close.level = RAW_CLOSE_CLOSE;
     311           3 :         cl.close.in.file.fnum = fnum;
     312           3 :         cl.close.in.write_time = 0;
     313           3 :         status = smb_raw_close(cli->tree, &cl);
     314           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     315             :                                         "smb_raw_close");
     316             : 
     317           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
     318           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     319             :                                         "smb_raw_changenotify_recv");
     320           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     321             :                                       0, ret, done, "no changes expected");
     322             : 
     323           3 : done:
     324           3 :         smb_raw_exit(cli->session);
     325           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_DIR);
     326           3 :         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          18 : 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           0 :         int i;
     343             : 
     344          36 :         for (i=0; i<3; i++) {
     345          36 :                 if (actions[i].action == action) {
     346          18 :                         CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
     347          18 :                         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           3 : static bool test_notify_recursive(struct torture_context *tctx,
     364             :                                   struct smbcli_state *cli,
     365             :                                   struct smbcli_state *cli2)
     366             : {
     367           3 :         bool ret = true;
     368           0 :         NTSTATUS status;
     369           0 :         union smb_notify notify;
     370           0 :         union smb_open io;
     371           0 :         int fnum;
     372           0 :         struct smbcli_request *req1, *req2;
     373             : 
     374           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY WITH RECURSION\n");
     375             : 
     376           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
     383           3 :         io.ntcreatex.in.root_fid.fnum = 0;
     384           3 :         io.ntcreatex.in.flags = 0;
     385           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
     386           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     387           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
     388           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
     389           3 :         io.ntcreatex.in.alloc_size = 0;
     390           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
     391           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
     392           3 :         io.ntcreatex.in.security_flags = 0;
     393           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_RECUR;
     394             : 
     395           3 :         status = smb_raw_open(cli->tree, tctx, &io);
     396           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     397             :                                         "smb_raw_open");
     398           3 :         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           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
     403           3 :         notify.nttrans.in.buffer_size = 1000;
     404           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
     405           3 :         notify.nttrans.in.file.fnum = fnum;
     406             : 
     407           3 :         notify.nttrans.in.recursive = true;
     408           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     409             : 
     410           3 :         notify.nttrans.in.recursive = false;
     411           3 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     412             : 
     413             :         /* cancel initial requests so the buffer is setup */
     414           3 :         smb_raw_ntcancel(req1);
     415           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     416           3 :         torture_assert_ntstatus_equal_goto(tctx, status,
     417             :                                            NT_STATUS_CANCELLED,
     418             :                                            ret, done,
     419             :                                            "smb_raw_changenotify_recv");
     420             : 
     421           3 :         smb_raw_ntcancel(req2);
     422           3 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     423           3 :         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           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name");
     433           3 :         smbcli_mkdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1");
     434           3 :         smbcli_close(cli->tree, 
     435             :                      smbcli_open(cli->tree,
     436             :                                 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
     437             :                                 O_CREAT, 0));
     438           3 :         smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1",
     439             :                       BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
     440           3 :         smbcli_rename(cli->tree,
     441             :                 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
     442             :                 BASEDIR_CN1_RECUR "\\subname2-r");
     443           3 :         smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subname2-r",
     444             :                       BASEDIR_CN1_RECUR "\\subname3-r");
     445             : 
     446           3 :         notify.nttrans.in.completion_filter = 0;
     447           3 :         notify.nttrans.in.recursive = true;
     448           3 :         smb_msleep(200);
     449           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     450             : 
     451           3 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
     452           3 :         smbcli_rmdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name");
     453           3 :         smbcli_unlink(cli->tree, BASEDIR_CN1_RECUR "\\subname3-r");
     454             : 
     455           3 :         smb_msleep(200);
     456           3 :         notify.nttrans.in.recursive = false;
     457           3 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     458             : 
     459           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     460           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     461             :                                         "smb_raw_changenotify_recv");
     462             : 
     463           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     464             :                                       11, ret, done, "wrong number of changes");
     465           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
     470             :                    STR_UNICODE);
     471           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name,
     476             :                    "subdir-name\\subname1", STR_UNICODE);
     477           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name,
     482             :                    "subdir-name\\subname2", STR_UNICODE);
     483           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name,
     488             :                    "subdir-name\\subname1", STR_UNICODE);
     489           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[4].name,
     494             :                    "subdir-name\\subname1-r", STR_UNICODE);
     495             : 
     496           6 :         ret &= check_rename_reply(tctx,
     497           3 :                 cli, __LINE__, &notify.nttrans.out.changes[5],
     498             :                 NOTIFY_ACTION_ADDED, "subname2-r");
     499           6 :         ret &= check_rename_reply(tctx,
     500           3 :                 cli, __LINE__, &notify.nttrans.out.changes[5],
     501             :                 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
     502           6 :         ret &= check_rename_reply(tctx,
     503           3 :                 cli, __LINE__, &notify.nttrans.out.changes[5],
     504             :                 NOTIFY_ACTION_MODIFIED, "subname2-r");
     505             :                 
     506           6 :         ret &= check_rename_reply(tctx,
     507           3 :                 cli, __LINE__, &notify.nttrans.out.changes[8],
     508             :                 NOTIFY_ACTION_OLD_NAME, "subname2-r");
     509           6 :         ret &= check_rename_reply(tctx,
     510           3 :                 cli, __LINE__, &notify.nttrans.out.changes[8],
     511             :                 NOTIFY_ACTION_NEW_NAME, "subname3-r");
     512           6 :         ret &= check_rename_reply(tctx,
     513           3 :                 cli, __LINE__, &notify.nttrans.out.changes[8],
     514             :                 NOTIFY_ACTION_MODIFIED, "subname3-r");
     515             : 
     516           3 :         if (!ret) {
     517           0 :                 goto done;
     518             :         }
     519             : 
     520           3 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     521           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     522             :                                         "smb_raw_changenotify_recv");
     523             : 
     524           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     525             :                                       3, ret, done, "wrong number of changes");
     526           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name,
     531             :                    "subdir-name\\subname1-r", STR_UNICODE);
     532           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
     537             :                    STR_UNICODE);
     538           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subname3-r",
     543             :                    STR_UNICODE);
     544             : 
     545           3 : done:
     546           3 :         smb_raw_exit(cli->session);
     547           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_RECUR);
     548           3 :         return ret;
     549             : }
     550             : 
     551             : /* 
     552             :    testing of change notify mask change
     553             : */
     554             : 
     555             : #define BASEDIR_CN1_CNMC BASEDIR "_CN1_CNMC"
     556             : 
     557           3 : static bool test_notify_mask_change(struct torture_context *tctx,
     558             :                                     struct smbcli_state *cli)
     559             : {
     560           3 :         bool ret = true;
     561           0 :         NTSTATUS status;
     562           0 :         union smb_notify notify;
     563           0 :         union smb_open io;
     564           0 :         int fnum;
     565           0 :         struct smbcli_request *req1, *req2;
     566             : 
     567           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
     568             : 
     569           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
     576           3 :         io.ntcreatex.in.root_fid.fnum = 0;
     577           3 :         io.ntcreatex.in.flags = 0;
     578           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
     579           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     580           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
     581           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
     582           3 :         io.ntcreatex.in.alloc_size = 0;
     583           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
     584           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
     585           3 :         io.ntcreatex.in.security_flags = 0;
     586           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_CNMC;
     587             : 
     588           3 :         status = smb_raw_open(cli->tree, tctx, &io);
     589           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     590             :                                         "smb_raw_open");
     591           3 :         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           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
     596           3 :         notify.nttrans.in.buffer_size = 1000;
     597           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
     598           3 :         notify.nttrans.in.file.fnum = fnum;
     599             : 
     600           3 :         notify.nttrans.in.recursive = true;
     601           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     602             : 
     603           3 :         notify.nttrans.in.recursive = false;
     604           3 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     605             : 
     606             :         /* cancel initial requests so the buffer is setup */
     607           3 :         smb_raw_ntcancel(req1);
     608           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     609           3 :         torture_assert_ntstatus_equal_goto(tctx, status,
     610             :                                            NT_STATUS_CANCELLED,
     611             :                                            ret, done,
     612             :                                            "smb_raw_changenotify_recv");
     613             : 
     614           3 :         smb_raw_ntcancel(req2);
     615           3 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     616           3 :         torture_assert_ntstatus_equal_goto(tctx, status,
     617             :                                            NT_STATUS_CANCELLED,
     618             :                                            ret, done,
     619             :                                            "smb_raw_changenotify_recv");
     620             : 
     621           3 :         notify.nttrans.in.recursive = true;
     622           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     623             : 
     624             :         /* Set to hidden then back again. */
     625           3 :         smbcli_close(cli->tree,
     626             :                 smbcli_open(cli->tree,BASEDIR_CN1_CNMC "\\tname1", O_CREAT, 0));
     627           3 :         smbcli_setatr(cli->tree, BASEDIR_CN1_CNMC "\\tname1",
     628             :                 FILE_ATTRIBUTE_HIDDEN, 0);
     629           3 :         smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\tname1");
     630             : 
     631           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     632           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     633             :                                         "smb_raw_changenotify_recv");
     634             : 
     635           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     636             :                                       1, ret, done, "wrong number of changes");
     637           3 :         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           3 :         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           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
     649           3 :         notify.nttrans.in.recursive = true;
     650           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
     651             : 
     652           3 :         notify.nttrans.in.recursive = false;
     653           3 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
     654             : 
     655           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
     656           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1");
     657           3 :         smbcli_close(cli->tree, 
     658             :                      smbcli_open(cli->tree,
     659             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
     660             :                         O_CREAT, 0));
     661           3 :         smbcli_rename(cli->tree,
     662             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname1",
     663             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
     664           3 :         smbcli_rename(cli->tree,
     665             :                         BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
     666             :                         BASEDIR_CN1_CNMC "\\subname2-r");
     667           3 :         smbcli_rename(cli->tree,
     668             :                         BASEDIR_CN1_CNMC "\\subname2-r",
     669             :                         BASEDIR_CN1_CNMC "\\subname3-r");
     670             : 
     671           3 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
     672           3 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
     673           3 :         smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\subname3-r");
     674             : 
     675           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
     676           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     677             :                                         "smb_raw_changenotify_recv");
     678             : 
     679           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     680             :                                       1, ret, done, "wrong number of changes");
     681           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname2-r",
     686             :                    STR_UNICODE);
     687             : 
     688           3 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
     689           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     690             :                                         "smb_raw_changenotify_recv");
     691             : 
     692           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
     693             :                                       1, ret, done, "wrong number of changes");
     694           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname3-r",
     699             :                    STR_UNICODE);
     700             : 
     701           3 : done:
     702           3 :         smb_raw_exit(cli->session);
     703           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_CNMC);
     704           3 :         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           3 : static bool test_notify_mask(struct torture_context *tctx,
     715             :                              struct smbcli_state *cli,
     716             :                              struct smbcli_state *cli2)
     717             : {
     718           3 :         bool ret = true;
     719           0 :         NTSTATUS status;
     720           0 :         union smb_notify notify;
     721           0 :         union smb_open io;
     722           0 :         union smb_chkpath chkpath;
     723           0 :         int fnum, fnum2;
     724           0 :         uint32_t mask;
     725           0 :         int i;
     726           3 :         char c = 1;
     727           0 :         struct timeval tv;
     728           0 :         NTTIME t;
     729             : 
     730           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
     731             : 
     732           3 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NOTM),
     733             :                        "Failed to setup up test directory: " BASEDIR_CN1_NOTM);
     734             : 
     735           3 :         tv = timeval_current_ofs(1000, 0);
     736           3 :         t = timeval_to_nttime(&tv);
     737             : 
     738             :         /*
     739             :           get a handle on the directory
     740             :         */
     741           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
     742           3 :         io.ntcreatex.in.root_fid.fnum = 0;
     743           3 :         io.ntcreatex.in.flags = 0;
     744           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
     745           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     746           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
     747           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
     748           3 :         io.ntcreatex.in.alloc_size = 0;
     749           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
     750           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
     751           3 :         io.ntcreatex.in.security_flags = 0;
     752           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_NOTM;
     753             : 
     754           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
     755           3 :         notify.nttrans.in.buffer_size = 1000;
     756           3 :         notify.nttrans.in.recursive = true;
     757             : 
     758           3 :         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           3 :         torture_comment(tctx, "Testing mkdir\n");
     831          99 :         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           0 :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
     836             : 
     837           3 :         torture_comment(tctx, "Testing create file\n");
     838          99 :         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           0 :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
     847             : 
     848           3 :         torture_comment(tctx, "Testing unlink\n");
     849          99 :         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           0 :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
     859             : 
     860           3 :         torture_comment(tctx, "Testing rmdir\n");
     861          99 :         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           0 :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
     867             : 
     868           3 :         torture_comment(tctx, "Testing rename file\n");
     869          99 :         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           0 :                          FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
     880             : 
     881           3 :         torture_comment(tctx, "Testing rename dir\n");
     882          99 :         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           0 :                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
     890             : 
     891           3 :         torture_comment(tctx, "Testing set path attribute\n");
     892          99 :         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           0 :                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
     901             : 
     902           3 :         torture_comment(tctx, "Testing set path write time\n");
     903          99 :         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           0 :                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
     912             : 
     913           3 :         torture_comment(tctx, "Testing set file attribute\n");
     914          99 :         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           0 :                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
     922             : 
     923           3 :         if (torture_setting_bool(tctx, "samba3", false)) {
     924           2 :                 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          33 :                 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           0 :                         FILE_NOTIFY_CHANGE_CREATION, 1);
     938             :         }
     939             : 
     940           3 :         torture_comment(tctx, "Testing set file access time\n");
     941          99 :         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           0 :                 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
     949             : 
     950           3 :         torture_comment(tctx, "Testing set file write time\n");
     951          99 :         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           0 :                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
     959             : 
     960           3 :         torture_comment(tctx, "Testing set file change time\n");
     961          99 :         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 :                 0, 1);
     969             : 
     970             : 
     971           3 :         torture_comment(tctx, "Testing write\n");
     972          99 :         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 :                 0, 1);
     980             : 
     981           3 :         torture_comment(tctx, "Testing truncate\n");
     982          99 :         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           0 :                 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
     990             : 
     991           3 : done:
     992           3 :         smb_raw_exit(cli->session);
     993           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NOTM);
     994           3 :         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           3 : static bool test_notify_file(struct torture_context *tctx,
    1004             :                              struct smbcli_state *cli)
    1005             : {
    1006           0 :         NTSTATUS status;
    1007           3 :         bool ret = true;
    1008           0 :         union smb_open io;
    1009           0 :         union smb_close cl;
    1010           0 :         union smb_notify notify;
    1011           0 :         struct smbcli_request *req;
    1012           0 :         int fnum;
    1013           3 :         const char *fname = BASEDIR_CN1_FILE "\\file.txt";
    1014             : 
    1015           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY ON FILES\n");
    1016             : 
    1017           3 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_FILE),
    1018             :                        "Failed to setup up test directory: " BASEDIR_CN1_FILE);
    1019             : 
    1020           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1021           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1022           3 :         io.ntcreatex.in.flags = 0;
    1023           3 :         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
    1024           3 :         io.ntcreatex.in.create_options = 0;
    1025           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1026           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1027           3 :         io.ntcreatex.in.alloc_size = 0;
    1028           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
    1029           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1030           3 :         io.ntcreatex.in.security_flags = 0;
    1031           3 :         io.ntcreatex.in.fname = fname;
    1032           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1033           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1034             :                                         "smb_raw_open");
    1035           3 :         fnum = io.ntcreatex.out.file.fnum;
    1036             : 
    1037             :         /* ask for a change notify,
    1038             :            on file or directory name changes */
    1039           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1040           3 :         notify.nttrans.in.file.fnum = fnum;
    1041           3 :         notify.nttrans.in.buffer_size = 1000;
    1042           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
    1043           3 :         notify.nttrans.in.recursive = false;
    1044             : 
    1045           3 :         torture_comment(tctx, "Testing if notifies on file handles are invalid (should be)\n");
    1046             : 
    1047           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1048           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1049           3 :         torture_assert_ntstatus_equal_goto(tctx, status,
    1050             :                                            NT_STATUS_INVALID_PARAMETER,
    1051             :                                            ret, done,
    1052             :                                            "smb_raw_changenotify_recv");
    1053             : 
    1054           3 :         cl.close.level = RAW_CLOSE_CLOSE;
    1055           3 :         cl.close.in.file.fnum = fnum;
    1056           3 :         cl.close.in.write_time = 0;
    1057           3 :         status = smb_raw_close(cli->tree, &cl);
    1058           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1059             :                                         "smb_raw_close");
    1060             : 
    1061           3 :         status = smbcli_unlink(cli->tree, fname);
    1062           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1063             :                                         "smbcli_unlink");
    1064             : 
    1065           3 : done:
    1066           3 :         smb_raw_exit(cli->session);
    1067           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_FILE);
    1068           3 :         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           3 : static bool test_notify_tdis(struct torture_context *tctx,
    1077             :                              struct smbcli_state *cli1)
    1078             : {
    1079           3 :         bool ret = true;
    1080           0 :         NTSTATUS status;
    1081           0 :         union smb_notify notify;
    1082           0 :         union smb_open io;
    1083           0 :         int fnum;
    1084           0 :         struct smbcli_request *req;
    1085           3 :         struct smbcli_state *cli = NULL;
    1086             : 
    1087           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
    1088             : 
    1089           3 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TDIS),
    1090             :                        "Failed to setup up test directory: " BASEDIR_CN1_TDIS);
    1091             : 
    1092           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1099           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1100           3 :         io.ntcreatex.in.flags = 0;
    1101           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1102           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1103           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1104           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1105           3 :         io.ntcreatex.in.alloc_size = 0;
    1106           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1107           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1108           3 :         io.ntcreatex.in.security_flags = 0;
    1109           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_TDIS;
    1110             : 
    1111           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1112           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1113             :                                         "smb_raw_open");
    1114           3 :         fnum = io.ntcreatex.out.file.fnum;
    1115             : 
    1116             :         /* ask for a change notify,
    1117             :            on file or directory name changes */
    1118           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1119           3 :         notify.nttrans.in.buffer_size = 1000;
    1120           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1121           3 :         notify.nttrans.in.file.fnum = fnum;
    1122           3 :         notify.nttrans.in.recursive = true;
    1123             : 
    1124           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1125             : 
    1126           3 :         status = smbcli_tdis(cli);
    1127           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1128             :                                         "smbcli_tdis");
    1129           3 :         cli->tree = NULL;
    1130             : 
    1131           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1132           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1133             :                                         "smb_raw_changenotify_recv");
    1134           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1135             :                                       0, ret, done, "no changes expected");
    1136             : 
    1137           3 : done:
    1138           3 :         torture_close_connection(cli);
    1139           3 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_TDIS);
    1140           3 :         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           3 : static bool test_notify_exit(struct torture_context *tctx,
    1150             :                              struct smbcli_state *cli1)
    1151             : {
    1152           3 :         bool ret = true;
    1153           0 :         NTSTATUS status;
    1154           0 :         union smb_notify notify;
    1155           0 :         union smb_open io;
    1156           0 :         int fnum;
    1157           0 :         struct smbcli_request *req;
    1158           3 :         struct smbcli_state *cli = NULL;
    1159             : 
    1160           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
    1161             : 
    1162           3 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_EX),
    1163             :                        "Failed to setup up test directory: " BASEDIR_CN1_EX);
    1164             : 
    1165           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1172           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1173           3 :         io.ntcreatex.in.flags = 0;
    1174           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1175           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1176           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1177           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1178           3 :         io.ntcreatex.in.alloc_size = 0;
    1179           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1180           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1181           3 :         io.ntcreatex.in.security_flags = 0;
    1182           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_EX;
    1183             : 
    1184           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1185           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1186             :                                         "smb_raw_open");
    1187           3 :         fnum = io.ntcreatex.out.file.fnum;
    1188             : 
    1189             :         /* ask for a change notify,
    1190             :            on file or directory name changes */
    1191           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1192           3 :         notify.nttrans.in.buffer_size = 1000;
    1193           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1194           3 :         notify.nttrans.in.file.fnum = fnum;
    1195           3 :         notify.nttrans.in.recursive = true;
    1196             : 
    1197           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1198             : 
    1199           3 :         status = smb_raw_exit(cli->session);
    1200           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1201             :                                         "smb_raw_exit");
    1202             : 
    1203           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1204           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1205             :                                         "smb_raw_changenotify_recv");
    1206           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1207             :                                       0, ret, done, "no changes expected");
    1208             : 
    1209           3 : done:
    1210           3 :         torture_close_connection(cli);
    1211           3 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_EX);
    1212           3 :         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           3 : static bool test_notify_ulogoff(struct torture_context *tctx,
    1222             :                                 struct smbcli_state *cli1)
    1223             : {
    1224           3 :         bool ret = true;
    1225           0 :         NTSTATUS status;
    1226           0 :         union smb_notify notify;
    1227           0 :         union smb_open io;
    1228           0 :         int fnum;
    1229           0 :         struct smbcli_request *req;
    1230           3 :         struct smbcli_state *cli = NULL;
    1231             : 
    1232           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
    1233             : 
    1234           3 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_UL),
    1235             :                        "Failed to setup up test directory: " BASEDIR_CN1_UL);
    1236             : 
    1237           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1244           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1245           3 :         io.ntcreatex.in.flags = 0;
    1246           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1247           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1248           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1249           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1250           3 :         io.ntcreatex.in.alloc_size = 0;
    1251           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1252           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1253           3 :         io.ntcreatex.in.security_flags = 0;
    1254           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_UL;
    1255             : 
    1256           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1257           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1258             :                                         "smb_raw_open");
    1259           3 :         fnum = io.ntcreatex.out.file.fnum;
    1260             : 
    1261             :         /* ask for a change notify,
    1262             :            on file or directory name changes */
    1263           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1264           3 :         notify.nttrans.in.buffer_size = 1000;
    1265           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1266           3 :         notify.nttrans.in.file.fnum = fnum;
    1267           3 :         notify.nttrans.in.recursive = true;
    1268             : 
    1269           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1270             : 
    1271           3 :         status = smb_raw_ulogoff(cli->session);
    1272           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1273             :                                         "smb_raw_ulogoff");
    1274             : 
    1275           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1276           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1277             :                                         "smb_raw_changenotify_recv");
    1278           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1279             :                                       0, ret, done, "no changes expected");
    1280             : 
    1281           3 : done:
    1282           3 :         torture_close_connection(cli);
    1283           3 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_UL);
    1284           3 :         return ret;
    1285             : }
    1286             : 
    1287           3 : static void tcp_dis_handler(struct smbcli_transport *t, void *p)
    1288             : {
    1289           3 :         struct smbcli_state *cli = (struct smbcli_state *)p;
    1290           3 :         smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
    1291           3 :         cli->transport = NULL;
    1292           3 :         cli->tree = NULL;
    1293           3 : }
    1294             : /*
    1295             :   basic testing of change notifies followed by tcp disconnect
    1296             : */
    1297             : 
    1298             : #define BASEDIR_CN1_TCPDIS BASEDIR "_CN1_TCPDIS"
    1299             : 
    1300           3 : static bool test_notify_tcp_dis(struct torture_context *tctx,
    1301             :                                 struct smbcli_state *cli1)
    1302             : {
    1303           3 :         bool ret = true;
    1304           0 :         NTSTATUS status;
    1305           0 :         union smb_notify notify;
    1306           0 :         union smb_open io;
    1307           0 :         int fnum;
    1308           0 :         struct smbcli_request *req;
    1309           3 :         struct smbcli_state *cli = NULL;
    1310             : 
    1311           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
    1312             : 
    1313           3 :         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TCPDIS),
    1314             :                        "Failed to setup up test directory: "
    1315             :                         BASEDIR_CN1_TCPDIS);
    1316             : 
    1317           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1324           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1325           3 :         io.ntcreatex.in.flags = 0;
    1326           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1327           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1328           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1329           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1330           3 :         io.ntcreatex.in.alloc_size = 0;
    1331           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1332           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1333           3 :         io.ntcreatex.in.security_flags = 0;
    1334           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_TCPDIS;
    1335             : 
    1336           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1337           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1338             :                                         "smb_raw_open");
    1339           3 :         fnum = io.ntcreatex.out.file.fnum;
    1340             : 
    1341             :         /* ask for a change notify,
    1342             :            on file or directory name changes */
    1343           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1344           3 :         notify.nttrans.in.buffer_size = 1000;
    1345           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1346           3 :         notify.nttrans.in.file.fnum = fnum;
    1347           3 :         notify.nttrans.in.recursive = true;
    1348             : 
    1349           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1350             : 
    1351           3 :         smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250000, cli);
    1352             : 
    1353           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1354           3 :         torture_assert_ntstatus_equal_goto(tctx, status,
    1355             :                                            NT_STATUS_LOCAL_DISCONNECT,
    1356             :                                            ret, done,
    1357             :                                            "smb_raw_changenotify_recv");
    1358             : 
    1359           3 : done:
    1360           3 :         torture_close_connection(cli);
    1361           3 :         smbcli_deltree(cli1->tree, BASEDIR_CN1_TCPDIS);
    1362           3 :         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           3 : static bool test_notify_double(struct torture_context *tctx,
    1372             :                                struct smbcli_state *cli)
    1373             : {
    1374           3 :         bool ret = true;
    1375           0 :         NTSTATUS status;
    1376           0 :         union smb_notify notify;
    1377           0 :         union smb_open io;
    1378           0 :         int fnum;
    1379           0 :         struct smbcli_request *req1, *req2;
    1380             : 
    1381           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
    1382             : 
    1383           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1390           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1391           3 :         io.ntcreatex.in.flags = 0;
    1392           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1393           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1394           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1395           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1396           3 :         io.ntcreatex.in.alloc_size = 0;
    1397           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1398           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1399           3 :         io.ntcreatex.in.security_flags = 0;
    1400           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_DBL;
    1401             : 
    1402           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1403           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1404             :                                         "smb_raw_open");
    1405           3 :         fnum = io.ntcreatex.out.file.fnum;
    1406             : 
    1407             :         /* ask for a change notify,
    1408             :            on file or directory name changes */
    1409           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1410           3 :         notify.nttrans.in.buffer_size = 1000;
    1411           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1412           3 :         notify.nttrans.in.file.fnum = fnum;
    1413           3 :         notify.nttrans.in.recursive = true;
    1414             : 
    1415           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1416           3 :         req2 = smb_raw_changenotify_send(cli->tree, &notify);
    1417             : 
    1418           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name");
    1419             : 
    1420           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1421           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1422             :                                         "smb_raw_changenotify_recv");
    1423           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1424             :                                       1, ret, done, "wrong number of changes");
    1425           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    1426             :                    STR_UNICODE);
    1427             : 
    1428           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name2");
    1429             : 
    1430           3 :         status = smb_raw_changenotify_recv(req2, tctx, &notify);
    1431           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1432             :                                         "smb_raw_changenotify_recv");
    1433           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1434             :                                       1, ret, done, "wrong number of changes");
    1435           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name2",
    1436             :                    STR_UNICODE);
    1437             : 
    1438           3 : done:
    1439           3 :         smb_raw_exit(cli->session);
    1440           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_DBL);
    1441           3 :         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           3 : static bool test_notify_tree(struct torture_context *tctx,
    1452             :                              struct smbcli_state *cli,
    1453             :                              struct smbcli_state *cli2)
    1454             : {
    1455           3 :         bool ret = true;
    1456           0 :         union smb_notify notify;
    1457           0 :         union smb_open io;
    1458           0 :         struct smbcli_request *req;
    1459           0 :         struct timeval tv;
    1460           0 :         struct {
    1461             :                 const char *path;
    1462             :                 bool recursive;
    1463             :                 uint32_t filter;
    1464             :                 int expected;
    1465             :                 int fnum;
    1466             :                 int counted;
    1467           3 :         } 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           0 :         int i;
    1590           0 :         NTSTATUS status;
    1591           3 :         bool all_done = false;
    1592             : 
    1593           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
    1594             : 
    1595           3 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_TNT),
    1596             :                        "Failed to setup up test directory: " BASEDIR_CN1_TNT);
    1597             : 
    1598           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1599           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1600           3 :         io.ntcreatex.in.flags = 0;
    1601           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1602           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1603           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1604           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1605           3 :         io.ntcreatex.in.alloc_size = 0;
    1606           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
    1607           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1608           3 :         io.ntcreatex.in.security_flags = 0;
    1609             : 
    1610           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1611           3 :         notify.nttrans.in.buffer_size = 20000;
    1612             : 
    1613             :         /*
    1614             :           setup the directory tree, and the notify buffer on each directory
    1615             :         */
    1616          63 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1617          60 :                 io.ntcreatex.in.fname = dirs[i].path;
    1618          60 :                 status = smb_raw_open(cli->tree, tctx, &io);
    1619          60 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1620             :                                                 "smb_raw_open");
    1621          60 :                 dirs[i].fnum = io.ntcreatex.out.file.fnum;
    1622             : 
    1623          60 :                 notify.nttrans.in.completion_filter = dirs[i].filter;
    1624          60 :                 notify.nttrans.in.file.fnum = dirs[i].fnum;
    1625          60 :                 notify.nttrans.in.recursive = dirs[i].recursive;
    1626          60 :                 req = smb_raw_changenotify_send(cli->tree, &notify);
    1627          60 :                 smb_raw_ntcancel(req);
    1628          60 :                 status = smb_raw_changenotify_recv(req, tctx, &notify);
    1629          60 :                 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          63 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1637          60 :                 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          60 :                 smbcli_mkdir(cli->tree, path);
    1644          60 :                 smbcli_rmdir(cli2->tree, path);
    1645          60 :                 talloc_free(path);
    1646             :         }
    1647             : 
    1648             :         /* give a bit of time for the events to propagate */
    1649           3 :         tv = timeval_current();
    1650             : 
    1651           0 :         do {
    1652             :                 /* count events that have happened in each dir */
    1653          63 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1654          60 :                         notify.nttrans.in.file.fnum = dirs[i].fnum;
    1655          60 :                         req = smb_raw_changenotify_send(cli->tree, &notify);
    1656          60 :                         smb_raw_ntcancel(req);
    1657          60 :                         notify.nttrans.out.num_changes = 0;
    1658          60 :                         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1659          60 :                         dirs[i].counted += notify.nttrans.out.num_changes;
    1660             :                 }
    1661             :                 
    1662           3 :                 all_done = true;
    1663             : 
    1664          63 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1665          60 :                         if (dirs[i].counted != dirs[i].expected) {
    1666           0 :                                 all_done = false;
    1667             :                         }
    1668             :                 }
    1669           3 :         } while (!all_done && timeval_elapsed(&tv) < 20);
    1670             : 
    1671           3 :         torture_comment(tctx, "took %.4f seconds to propagate all events\n", timeval_elapsed(&tv));
    1672             : 
    1673          63 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    1674          60 :                 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          63 :         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
    1685          60 :                 smbcli_close(cli->tree, dirs[i].fnum);
    1686          60 :                 smbcli_rmdir(cli->tree, dirs[i].path);
    1687             :         }
    1688             : 
    1689           3 : done:
    1690           3 :         smb_raw_exit(cli->session);
    1691           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_TNT);
    1692           3 :         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           3 : static bool test_notify_overflow(struct torture_context *tctx,
    1703             :                                  struct smbcli_state *cli)
    1704             : {
    1705           3 :         bool ret = true;
    1706           0 :         NTSTATUS status;
    1707           0 :         union smb_notify notify;
    1708           0 :         union smb_open io;
    1709           0 :         int fnum;
    1710           3 :         int count = 100;
    1711           0 :         struct smbcli_request *req1;
    1712           0 :         int i;
    1713             : 
    1714           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
    1715             : 
    1716           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1721           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1722           3 :         io.ntcreatex.in.flags = 0;
    1723           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1724           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1725           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1726           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1727             :             NTCREATEX_SHARE_ACCESS_WRITE;
    1728           3 :         io.ntcreatex.in.alloc_size = 0;
    1729           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1730           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1731           3 :         io.ntcreatex.in.security_flags = 0;
    1732           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_NO;
    1733             : 
    1734           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1735           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1736             :                                         "smb_raw_open");
    1737           3 :         fnum = io.ntcreatex.out.file.fnum;
    1738             : 
    1739             :         /* ask for a change notify, on name changes. */
    1740           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1741           3 :         notify.nttrans.in.buffer_size = 1000;
    1742           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1743           3 :         notify.nttrans.in.file.fnum = fnum;
    1744             : 
    1745           3 :         notify.nttrans.in.recursive = true;
    1746           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1747             : 
    1748             :         /* cancel initial requests so the buffer is setup */
    1749           3 :         smb_raw_ntcancel(req1);
    1750           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1751           3 :         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           3 :         torture_comment(tctx, "Testing overflowed buffer notify on create of %d files\n",
    1758             :                count);
    1759         303 :         for (i=0;i<count;i++) {
    1760         300 :                 char *fname = talloc_asprintf(cli,
    1761             :                                 BASEDIR_CN1_NO "\\test%d.txt", i);
    1762         300 :                 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
    1763             :                                         DENY_NONE);
    1764         300 :                 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         300 :                 talloc_free(fname);
    1768         300 :                 smbcli_close(cli->tree, fnum2);
    1769             :         }
    1770             : 
    1771             :         /* expect that 0 events will be returned with NT_STATUS_OK */
    1772           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1773           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1774           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1775             :                                         "smb_raw_changenotify_recv");
    1776           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1777             :                                       0, ret, done, "no changes expected");
    1778             : 
    1779           3 : done:
    1780           3 :         smb_raw_exit(cli->session);
    1781           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NO);
    1782           3 :         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           3 : static bool test_notify_basedir(struct torture_context *tctx,
    1793             :                                 struct smbcli_state *cli)
    1794             : {
    1795           3 :         bool ret = true;
    1796           0 :         NTSTATUS status;
    1797           0 :         union smb_notify notify;
    1798           0 :         union smb_open io;
    1799           0 :         int fnum;
    1800           0 :         struct smbcli_request *req1;
    1801             : 
    1802           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
    1803             : 
    1804           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1809           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1810           3 :         io.ntcreatex.in.flags = 0;
    1811           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1812           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1813           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1814           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1815             :             NTCREATEX_SHARE_ACCESS_WRITE;
    1816           3 :         io.ntcreatex.in.alloc_size = 0;
    1817           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1818           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1819           3 :         io.ntcreatex.in.security_flags = 0;
    1820           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_NBASE;
    1821             : 
    1822           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1823           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1824             :                                         "smb_raw_open");
    1825           3 :         fnum = io.ntcreatex.out.file.fnum;
    1826             : 
    1827             :         /* create a test file that will also be modified */
    1828           3 :         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           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1834           3 :         notify.nttrans.in.buffer_size = 1000;
    1835           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
    1836           3 :         notify.nttrans.in.file.fnum = fnum;
    1837           3 :         notify.nttrans.in.recursive = true;
    1838             : 
    1839           3 :         req1 = smb_raw_changenotify_send(cli->tree, &notify);
    1840             : 
    1841             :         /* set attribute on the base dir */
    1842           3 :         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           3 :         smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE "\\tname1",
    1846             :                         FILE_ATTRIBUTE_HIDDEN, 0);
    1847           3 :         smb_msleep(200);
    1848             : 
    1849             :         /* check how many responses were given, expect only 1 for the file */
    1850           3 :         status = smb_raw_changenotify_recv(req1, tctx, &notify);
    1851           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1852             :                                         "smb_raw_changenotify_recv");
    1853           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1854             :                                       1, ret, done, "wrong number of  changes");
    1855           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
    1860             :                    STR_UNICODE);
    1861             : 
    1862           3 : done:
    1863           3 :         smb_raw_exit(cli->session);
    1864           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NBASE);
    1865           3 :         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           3 : static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli, 
    1875             :                                           struct torture_context *tctx)
    1876             : {
    1877           0 :         NTSTATUS status;
    1878           0 :         const char *share, *host;
    1879           0 :         struct smbcli_tree *tree;
    1880           0 :         union smb_tcon tcon;
    1881             : 
    1882           3 :         share = torture_setting_string(tctx, "share", NULL);
    1883           3 :         host  = torture_setting_string(tctx, "host", NULL);
    1884             :         
    1885           3 :         torture_comment(tctx, "create a second tree context on the same session\n");
    1886           3 :         tree = smbcli_tree_init(cli->session, tctx, false);
    1887             : 
    1888           3 :         tcon.generic.level = RAW_TCON_TCONX;
    1889           3 :         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
    1890           3 :         tcon.tconx.in.password = data_blob(NULL, 0);
    1891           3 :         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
    1892           3 :         tcon.tconx.in.device = "A:";  
    1893           3 :         status = smb_raw_tcon(tree, tctx, &tcon);
    1894           3 :         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           3 :         tree->tid = tcon.tconx.out.tid;
    1901           3 :         torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
    1902             : 
    1903           3 :         return tree;
    1904             : }
    1905             : 
    1906             : 
    1907             : /* 
    1908             :    very simple change notify test
    1909             : */
    1910             : 
    1911             : #define BASEDIR_CN1_NTCON BASEDIR "_CN1_NTCON"
    1912             : 
    1913           3 : static bool test_notify_tcon(struct torture_context *tctx,
    1914             :                              struct smbcli_state *cli)
    1915             : {
    1916           3 :         bool ret = true;
    1917           0 :         NTSTATUS status;
    1918           0 :         union smb_notify notify;
    1919           0 :         union smb_open io;
    1920           0 :         int fnum;
    1921           0 :         struct smbcli_request *req;
    1922           0 :         extern int torture_numops;
    1923           3 :         struct smbcli_tree *tree = NULL;
    1924             :                 
    1925           3 :         torture_comment(tctx, "TESTING SIMPLE CHANGE NOTIFY\n");
    1926             : 
    1927           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    1934           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    1935           3 :         io.ntcreatex.in.flags = 0;
    1936           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    1937           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1938           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    1939           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
    1940           3 :         io.ntcreatex.in.alloc_size = 0;
    1941           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    1942           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1943           3 :         io.ntcreatex.in.security_flags = 0;
    1944           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_NTCON;
    1945             : 
    1946           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1947           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1948             :                                         "smb_raw_open");
    1949           3 :         fnum = io.ntcreatex.out.file.fnum;
    1950             : 
    1951           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    1952           3 :         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           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    1958           3 :         notify.nttrans.in.buffer_size = 1000;
    1959           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1960           3 :         notify.nttrans.in.file.fnum = fnum;
    1961           3 :         notify.nttrans.in.recursive = true;
    1962             : 
    1963           3 :         torture_comment(tctx, "Testing notify mkdir\n");
    1964           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1965           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    1966             : 
    1967           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1968           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1969             :                                         "smb_raw_changenotify_recv");
    1970             : 
    1971           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1972             :                                       1, ret, done, "wrong number of changes");
    1973           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    1978             :                    STR_UNICODE);
    1979             : 
    1980           3 :         torture_comment(tctx, "Testing notify rmdir\n");
    1981           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    1982           3 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    1983             : 
    1984           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    1985           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1986             :                                         "smb_raw_changenotify_recv");
    1987           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    1988             :                                       1, ret, done, "wrong number of changes");
    1989           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    1994             :                    STR_UNICODE);
    1995             : 
    1996           3 :         torture_comment(tctx, "SIMPLE CHANGE NOTIFY OK\n");
    1997             : 
    1998           3 :         torture_comment(tctx, "TESTING WITH SECONDARY TCON\n");
    1999           3 :         tree = secondary_tcon(cli, tctx);
    2000           3 :         torture_assert_not_null_goto(tctx, tree, ret, done,
    2001             :                                      "failed to create secondary tcon");
    2002             : 
    2003           3 :         torture_comment(tctx, "Testing notify mkdir\n");
    2004           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2005           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2006             : 
    2007           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2008           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2009             :                                         "smb_raw_changenotify_recv");
    2010             : 
    2011           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2012             :                                       1, ret, done, "wrong number of changes");
    2013           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2018             :                    STR_UNICODE);
    2019             : 
    2020           3 :         torture_comment(tctx, "Testing notify rmdir\n");
    2021           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2022           3 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2023             : 
    2024           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2025           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2026             :                                         "smb_raw_changenotify_recv");
    2027           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2028             :                                       1, ret, done, "wrong number of changes");
    2029           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2034             :                    STR_UNICODE);
    2035             : 
    2036           3 :         torture_comment(tctx, "CHANGE NOTIFY WITH TCON OK\n");
    2037             : 
    2038           3 :         torture_comment(tctx, "Disconnecting secondary tree\n");
    2039           3 :         status = smb_tree_disconnect(tree);
    2040           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2041             :                                         "smb_tree_disconnect");
    2042           3 :         talloc_free(tree);
    2043             : 
    2044           3 :         torture_comment(tctx, "Testing notify mkdir\n");
    2045           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2046           3 :         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2047             : 
    2048           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2049           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2050             :                                         "smb_raw_changenotify_recv");
    2051             : 
    2052           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2053             :                                       1, ret, done, "wrong number of changes");
    2054           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2059             :                    STR_UNICODE);
    2060             : 
    2061           3 :         torture_comment(tctx, "Testing notify rmdir\n");
    2062           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2063           3 :         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
    2064             : 
    2065           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2066           3 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2067             :                                         "smb_raw_changenotify_recv");
    2068           3 :         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
    2069             :                                       1, ret, done, "wrong number of changes");
    2070           3 :         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           3 :         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
    2075             :                    STR_UNICODE);
    2076             : 
    2077           3 :         torture_comment(tctx, "CHANGE NOTIFY WITH TDIS OK\n");
    2078           3 : done:
    2079           3 :         smb_raw_exit(cli->session);
    2080           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NTCON);
    2081           3 :         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           3 : static bool test_notify_alignment(struct torture_context *tctx,
    2106             :                                   struct smbcli_state *cli)
    2107             : {
    2108           0 :         NTSTATUS status;
    2109           0 :         union smb_notify notify;
    2110           0 :         union smb_open io;
    2111           0 :         int fnum, fnum2;
    2112           0 :         struct smbcli_request *req;
    2113           3 :         const char *fname = BASEDIR_CN1_NALIGN "\\starter";
    2114           3 :         const char *fnames[] = { "a",
    2115             :                                  "ab",
    2116             :                                  "abc",
    2117             :                                  "abcd" };
    2118           3 :         bool fnames_received[] = {false,
    2119             :                                   false,
    2120             :                                   false,
    2121             :                                   false};
    2122           3 :         size_t total_names_received = 0;
    2123           3 :         size_t num_names = ARRAY_SIZE(fnames);
    2124           0 :         size_t i;
    2125           3 :         char *fpath = NULL;
    2126             : 
    2127           3 :         torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
    2128             : 
    2129           3 :         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           3 :         io.generic.level = RAW_OPEN_NTCREATEX;
    2134           3 :         io.ntcreatex.in.root_fid.fnum = 0;
    2135           3 :         io.ntcreatex.in.flags = 0;
    2136           3 :         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
    2137           3 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2138           3 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
    2139           3 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2140             :                                        NTCREATEX_SHARE_ACCESS_WRITE;
    2141           3 :         io.ntcreatex.in.alloc_size = 0;
    2142           3 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    2143           3 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
    2144           3 :         io.ntcreatex.in.security_flags = 0;
    2145           3 :         io.ntcreatex.in.fname = BASEDIR_CN1_NALIGN;
    2146             : 
    2147           3 :         status = smb_raw_open(cli->tree, tctx, &io);
    2148           3 :         torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
    2149           3 :         fnum = io.ntcreatex.out.file.fnum;
    2150             : 
    2151             :         /* ask for a change notify, on file creation */
    2152           3 :         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
    2153           3 :         notify.nttrans.in.buffer_size = 1000;
    2154           3 :         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
    2155           3 :         notify.nttrans.in.file.fnum = fnum;
    2156           3 :         notify.nttrans.in.recursive = false;
    2157             : 
    2158             :         /* start change tracking */
    2159           3 :         req = smb_raw_changenotify_send(cli->tree, &notify);
    2160             : 
    2161           3 :         fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
    2162           3 :         torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
    2163           3 :         smbcli_close(cli->tree, fnum2);
    2164             : 
    2165           3 :         status = smb_raw_changenotify_recv(req, tctx, &notify);
    2166           3 :         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          15 :         for (i = 0; i < num_names; i++) {
    2174          12 :                 fpath = talloc_asprintf(tctx, "%s\\%s",
    2175             :                                 BASEDIR_CN1_NALIGN, fnames[i]);
    2176          12 :                 fnum2 = smbcli_open(cli->tree, fpath,
    2177             :                     O_CREAT|O_RDWR, DENY_NONE);
    2178          12 :                 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
    2179          12 :                 smbcli_close(cli->tree, fnum2);
    2180          12 :                 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           6 :         while (total_names_received < num_names) {
    2189           3 :                 struct tevent_timer *te = NULL;
    2190           3 :                 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           3 :                 req = smb_raw_changenotify_send(cli->tree, &notify);
    2198           3 :                 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           3 :                 to_data.req = req;
    2204           3 :                 to_data.timed_out = false;
    2205             : 
    2206           3 :                 te = tevent_add_timer(tctx->ev,
    2207             :                                 req,
    2208             :                                 tevent_timeval_current_ofs(30, 0),
    2209             :                                 timeout_cb,
    2210             :                                 &to_data);
    2211           3 :                 if (te == NULL) {
    2212           0 :                         torture_fail(tctx, "tevent_add_timer fail\n");
    2213             :                 }
    2214             : 
    2215           3 :                 status = smb_raw_changenotify_recv(req, tctx, &notify);
    2216           3 :                 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           3 :                 torture_assert_ntstatus_ok(tctx, status,
    2224             :                         "smb_raw_changenotify_recv");
    2225             : 
    2226          15 :                 for (i = 0; i < notify.nttrans.out.num_changes; i++) {
    2227           0 :                         size_t j;
    2228             : 
    2229             :                         /* Ensure it was an 'add'. */
    2230          12 :                         torture_assert(tctx,
    2231             :                                 notify.nttrans.out.changes[i].action ==
    2232             :                                         NOTIFY_ACTION_ADDED,
    2233             :                                 "");
    2234             : 
    2235          30 :                         for (j = 0; j < num_names; j++) {
    2236          30 :                                 if (strcmp(notify.nttrans.out.changes[i].name.s,
    2237             :                                                 fnames[j]) == 0) {
    2238          12 :                                         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          12 :                                         fnames_received[j] = true;
    2253          12 :                                         break;
    2254             :                                 }
    2255             :                         }
    2256          12 :                         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          12 :                         total_names_received++;
    2267             :                 }
    2268             :         }
    2269             : 
    2270           3 :         smb_raw_exit(cli->session);
    2271           3 :         smbcli_deltree(cli->tree, BASEDIR_CN1_NALIGN);
    2272           3 :         return true;
    2273             : }
    2274             : 
    2275        2379 : struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
    2276             : {
    2277        2379 :         struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
    2278             : 
    2279        2379 :         torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
    2280        2379 :         torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
    2281        2379 :         torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
    2282        2379 :         torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
    2283        2379 :         torture_suite_add_1smb_test(suite, "mask_change",
    2284             :                                     test_notify_mask_change);
    2285        2379 :         torture_suite_add_1smb_test(suite, "file", test_notify_file);
    2286        2379 :         torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
    2287        2379 :         torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
    2288        2379 :         torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
    2289        2379 :         torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
    2290        2379 :         torture_suite_add_1smb_test(suite, "double", test_notify_double);
    2291        2379 :         torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
    2292        2379 :         torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
    2293        2379 :         torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
    2294        2379 :         torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);
    2295             : 
    2296        2379 :         return suite;
    2297             : }

Generated by: LCOV version 1.14