smbtorture: Add smb2.maxfid
[metze/samba/wip.git] / source4 / torture / smb2 / maxfid.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    SMB2 maxfid test
5
6    Copyright (C) Christof Schmitt 2016
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28
29 bool torture_smb2_maxfid(struct torture_context *tctx)
30 {
31         bool ret = true;
32         NTSTATUS status;
33         struct smb2_tree *tree = NULL;
34         const char *dname = "smb2_maxfid";
35         int i, maxfid;
36         struct smb2_handle *handles,  dir_handle = { };
37         const size_t max_handles = 0x41000; /* Windows 8.1 allowed 0x40000 */
38
39         if (!torture_smb2_connection(tctx, &tree)) {
40                 return false;
41         }
42
43         handles = talloc_array(tctx, struct smb2_handle, max_handles);
44         if (handles == 0) {
45                 torture_fail(tctx, "Could not allocate handles array.\n");
46                 return false;
47         }
48
49         smb2_deltree(tree, dname);
50
51         status = torture_smb2_testdir(tree, dname, &dir_handle);
52         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
53                                         "torture_smb2_testdir failed");
54         smb2_util_close(tree, dir_handle);
55
56         torture_comment(tctx, "Creating subdirectories\n");
57
58         for (i = 0; i < max_handles; i += 1000) {
59                 char *name;
60                 struct smb2_create create = { };
61                 struct smb2_close close = { };
62
63                 name = talloc_asprintf(tctx, "%s\\%d", dname, i / 1000);
64                 torture_assert_goto(tctx, (name != NULL), ret, done,
65                                     "no memory for directory name\n");
66
67                 create.in.desired_access = SEC_RIGHTS_DIR_ALL;
68                 create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
69                 create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
70                 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
71                         NTCREATEX_SHARE_ACCESS_WRITE |
72                         NTCREATEX_SHARE_ACCESS_DELETE;
73                 create.in.create_disposition = NTCREATEX_DISP_CREATE;
74                 create.in.fname = name;
75
76                 status = smb2_create(tree, tctx, &create);
77                 talloc_free(name);
78
79                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
80                                                 "CREATE directory failed\n");
81
82                 close.in.file.handle = create.out.file.handle;
83                 status = smb2_close(tree, &close);
84                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
85                                                 "CLOSE directory failed\n");
86         }
87
88         torture_comment(tctx, "Testing maximum number of open files\n");
89
90         for (i = 0; i < max_handles; i++) {
91                 char *name;
92                 struct smb2_create create = { };
93
94                 name = talloc_asprintf(tctx, "%s\\%d\\%d", dname, i / 1000, i);
95                 torture_assert_goto(tctx, (name != NULL), ret, done,
96                                     "no memory for file name\n");
97
98                 create.in.desired_access = SEC_RIGHTS_DIR_ALL;
99                 create.in.create_options = 0;
100                 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
101                 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
102                         NTCREATEX_SHARE_ACCESS_WRITE |
103                         NTCREATEX_SHARE_ACCESS_DELETE;
104                 create.in.create_disposition = NTCREATEX_DISP_CREATE;
105                 create.in.fname = name;
106
107                 status = smb2_create(tree, tctx, &create);
108                 if (!NT_STATUS_IS_OK(status)) {
109                         torture_comment(tctx, "create of %s failed: %s\n",
110                                         name, nt_errstr(status));
111                         talloc_free(name);
112                         break;
113                 }
114                 talloc_free(name);
115
116                 handles[i] = create.out.file.handle;
117         }
118
119         maxfid = i;
120         torture_comment(tctx, "Maximum number of open files: %d\n", maxfid);
121
122         torture_comment(tctx, "Cleanup open files\n");
123
124         for (i = 0; i < maxfid; i++) {
125                 union smb_setfileinfo sfinfo = { };
126
127                 sfinfo.disposition_info.in.delete_on_close = 1;
128                 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
129                 sfinfo.generic.in.file.handle = handles[i];
130
131                 status = smb2_setinfo_file(tree, &sfinfo);
132                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
133                                                 "SETINFO failed\n");
134
135                 status = smb2_util_close(tree, handles[i]);
136                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
137                                                 "CLOSE failed\n");
138         }
139
140 done:
141         smb2_deltree(tree, dname);
142         talloc_free(handles);
143
144         return ret;
145 }