Convert libcli routines to use cli_tree instead of cli_state. Port
[kamenim/samba.git] / source4 / torture / torture_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester utility functions
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23
24 static struct timeval tp1,tp2;
25
26 void start_timer(void)
27 {
28         gettimeofday(&tp1,NULL);
29 }
30
31 double end_timer(void)
32 {
33         gettimeofday(&tp2,NULL);
34         return((tp2.tv_sec - tp1.tv_sec) + 
35                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
36 }
37
38
39 /*
40   create a directory, returning a handle to it
41 */
42 int create_directory_handle(struct cli_tree *tree, const char *dname)
43 {
44         NTSTATUS status;
45         union smb_open io;
46         TALLOC_CTX *mem_ctx;
47
48         mem_ctx = talloc_init("create_directory_handle");
49
50         io.generic.level = RAW_OPEN_NTCREATEX;
51         io.ntcreatex.in.root_fid = 0;
52         io.ntcreatex.in.flags = 0;
53         io.ntcreatex.in.access_mask = SA_RIGHT_FILE_ALL_ACCESS;
54         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
55         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
56         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
57         io.ntcreatex.in.alloc_size = 0;
58         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
59         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
60         io.ntcreatex.in.security_flags = 0;
61         io.ntcreatex.in.fname = dname;
62
63         status = smb_raw_open(tree, mem_ctx, &io);
64         if (!NT_STATUS_IS_OK(status)) {
65                 talloc_destroy(mem_ctx);
66                 return -1;
67         }
68
69         talloc_destroy(mem_ctx);
70         return io.ntcreatex.out.fnum;
71 }
72
73 /*
74   sometimes we need a fairly complex file to work with, so we can test
75   all possible attributes. 
76 */
77 int create_complex_file(struct cli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
78 {
79         int fnum;
80         char buf[7] = "abc";
81         union smb_setfileinfo setfile;
82         union smb_fileinfo fileinfo;
83         time_t t = (time(NULL) & ~1);
84         NTSTATUS status;
85
86         cli_unlink(cli->tree, fname);
87         fnum = cli_nt_create_full(cli->tree, fname, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
88                                   FILE_ATTRIBUTE_NORMAL,
89                                   NTCREATEX_SHARE_ACCESS_DELETE|
90                                   NTCREATEX_SHARE_ACCESS_READ|
91                                   NTCREATEX_SHARE_ACCESS_WRITE, 
92                                   NTCREATEX_DISP_OVERWRITE_IF,
93                                   0, 0);
94         if (fnum == -1) return -1;
95
96         cli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
97
98         /* setup some EAs */
99         setfile.generic.level = RAW_SFILEINFO_EA_SET;
100         setfile.generic.file.fnum = fnum;
101         setfile.ea_set.in.ea.flags = 0;
102         setfile.ea_set.in.ea.name.s = "EAONE";
103         setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "VALUE1", 6);
104
105         status = smb_raw_setfileinfo(cli->tree, &setfile);
106         if (!NT_STATUS_IS_OK(status)) {
107                 printf("Failed to setup EAs\n");
108         }
109
110         setfile.ea_set.in.ea.name.s = "SECONDEA";
111         setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
112         status = smb_raw_setfileinfo(cli->tree, &setfile);
113         if (!NT_STATUS_IS_OK(status)) {
114                 printf("Failed to setup EAs\n");
115         }
116
117         /* make sure all the timestamps aren't the same */
118         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
119         setfile.generic.file.fnum = fnum;
120
121         setfile.setattre.in.create_time = t + 60;
122         setfile.setattre.in.access_time = t + 120;
123         setfile.setattre.in.write_time  = t + 180;
124
125         status = smb_raw_setfileinfo(cli->tree, &setfile);
126         if (!NT_STATUS_IS_OK(status)) {
127                 printf("Failed to setup file times - %s\n", nt_errstr(status));
128         }
129
130         /* make sure all the timestamps aren't the same */
131         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
132         fileinfo.generic.in.fnum = fnum;
133
134         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
135         if (!NT_STATUS_IS_OK(status)) {
136                 printf("Failed to query file times - %s\n", nt_errstr(status));
137         }
138
139         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
140                 printf("create_time not setup correctly\n");
141         }
142         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
143                 printf("access_time not setup correctly\n");
144         }
145         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
146                 printf("write_time not setup correctly\n");
147         }
148
149         return fnum;
150 }
151
152
153
154 /* return a pointer to a anonymous shared memory segment of size "size"
155    which will persist across fork() but will disappear when all processes
156    exit 
157
158    The memory is not zeroed 
159
160    This function uses system5 shared memory. It takes advantage of a property
161    that the memory is not destroyed if it is attached when the id is removed
162    */
163 void *shm_setup(int size)
164 {
165         int shmid;
166         void *ret;
167
168         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
169         if (shmid == -1) {
170                 printf("can't get shared memory\n");
171                 exit(1);
172         }
173         ret = (void *)shmat(shmid, 0, 0);
174         if (!ret || ret == (void *)-1) {
175                 printf("can't attach to shared memory\n");
176                 return NULL;
177         }
178         /* the following releases the ipc, but note that this process
179            and all its children will still have access to the memory, its
180            just that the shmid is no longer valid for other shm calls. This
181            means we don't leave behind lots of shm segments after we exit 
182
183            See Stevens "advanced programming in unix env" for details
184            */
185         shmctl(shmid, IPC_RMID, 0);
186         
187         return ret;
188 }
189
190
191 /*
192   check that a wire string matches the flags specified 
193   not 100% accurate, but close enough for testing
194 */
195 BOOL wire_bad_flags(WIRE_STRING *str, int flags)
196 {
197         int len;
198         if (!str || !str->s) return True;
199         len = strlen(str->s);
200         if (flags & STR_TERMINATE) len++;
201         if ((flags & STR_UNICODE) || !getenv("CLI_FORCE_ASCII")) {
202                 len *= 2;
203         } else if (flags & STR_TERMINATE_ASCII) {
204                 len++;
205         }
206         if (str->private_length != len) {
207                 printf("Expected wire_length %d but got %d for '%s'\n", 
208                        len, str->private_length, str->s);
209                 return True;
210         }
211         return False;
212 }
213
214 /*
215   return a talloced string representing a time_t for human consumption
216 */
217 const char *time_string(TALLOC_CTX *mem_ctx, time_t t)
218 {
219         return talloc_strdup(mem_ctx, http_timestring(mem_ctx, t));
220 }
221
222 /*
223   check if 2 NTTIMEs are equal
224 */
225 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
226 {
227         return t1->low == t2->low && t1->high == t2->high;
228 }
229
230 /*
231   dump a all_info QFILEINFO structure
232 */
233 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
234 {
235         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.create_time));
236         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.access_time));
237         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.write_time));
238         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.change_time));
239         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
240         d_printf("\talloc_size:     %llu\n", (unsigned long long)finfo->all_info.out.alloc_size);
241         d_printf("\tsize:           %llu\n", (unsigned long long)finfo->all_info.out.size);
242         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
243         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
244         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
245         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
246         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
247 }
248
249 /*
250   dump file infor by name
251 */
252 void torture_all_info(struct cli_tree *tree, const char *fname)
253 {
254         TALLOC_CTX *mem_ctx = talloc_init(fname);
255         union smb_fileinfo finfo;
256         NTSTATUS status;
257
258         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
259         finfo.generic.in.fname = fname;
260         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
261         if (!NT_STATUS_IS_OK(status)) {
262                 d_printf("%s - %s\n", fname, nt_errstr(status));
263                 return;
264         }
265
266         d_printf("%s:\n", fname);
267         dump_all_info(mem_ctx, &finfo);
268         talloc_destroy(mem_ctx);
269 }
270
271
272 /*
273   split a UNC name into server and share names
274 */
275 BOOL split_unc_name(const char *unc, char **server, char **share)
276 {
277         char *p = strdup(unc);
278         if (!p) return False;
279         all_string_sub(p, "\\", "/", 0);
280         if (strncmp(p, "//", 2) != 0) return False;
281
282         (*server) = p+2;
283         p = strchr(*server, '/');
284         if (!p) return False;
285
286         *p = 0;
287         (*share) = p+1;
288         
289         return True;
290 }
291
292 /*
293   split a USER%PASS pair into username and password
294 */
295 BOOL split_username(const char *pair, char **user, char **pass)
296 {
297         char *p = strdup(pair);
298         if (!p) return False;
299
300         (*user) = p;
301
302         p = strchr(*user, '%');
303         if (!p) return False;
304
305         *p = 0;
306         (*pass) = p+1;
307         
308         return True;
309 }
310
311 /*
312   set a attribute on a file
313 */
314 BOOL torture_set_file_attribute(struct cli_tree *tree, const char *fname, uint16 attrib)
315 {
316         union smb_setfileinfo sfinfo;
317         NTSTATUS status;
318
319         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
320         sfinfo.generic.file.fname = fname;
321
322         ZERO_STRUCT(sfinfo.basic_info.in);
323         sfinfo.basic_info.in.attrib = attrib;
324         status = smb_raw_setpathinfo(tree, &sfinfo);
325         return NT_STATUS_IS_OK(status);
326 }
327
328
329 /*
330   set a file descriptor as sparse
331 */
332 NTSTATUS torture_set_sparse(struct cli_tree *tree, int fnum)
333 {
334         union smb_ioctl nt;
335         NTSTATUS status;
336         TALLOC_CTX *mem_ctx;
337
338         mem_ctx = talloc_init("torture_set_sparse");
339         if (!mem_ctx) {
340                 return NT_STATUS_NO_MEMORY;
341         }
342
343         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
344         nt.ntioctl.in.function = 0x900c4;
345         nt.ntioctl.in.fnum = fnum;
346         nt.ntioctl.in.fsctl = True;
347         nt.ntioctl.in.filter = 0;
348
349         status = smb_raw_ioctl(tree, mem_ctx, &nt);
350
351         talloc_destroy(mem_ctx);
352
353         return status;
354 }